Why Extract & Export XM Directory Mappings?
If you work with Qualtrics Workflows and XM Directory, the Update XM Directory Contacts task is one of the most powerful data integration tools available. It maps survey responses, embedded data and transaction metadata directly into your directory contacts.
Managing these mappings across multiple workflows is where things get painful:
- Manually documenting which source fields map to which directory fields is slow and error-prone
- Transaction data mappings involve extra complexity with the "Make Piped Text" setting
- Migrating workflows between environments requires exact mapping documentation
- Audit and compliance requirements demand comprehensive, reproducible records
This guide gives you a free browser-based script that extracts all your contact and transaction mappings in seconds and exports them as clean CSV files.
| Screen | What it captures | Output file |
|---|---|---|
| Part 1: Confirm import fields | Source Field → XM Directory contact fields | xm_contact_mappings.csv |
| Part 2: Map specific values | Source Field → Transaction fields + Make Piped Text status | xm_transaction_mappings.csv |
Part 1: Extract Contact Mappings
Watch the Demo
Open the Workflow Task
In Qualtrics, navigate to the Workflows tab in your project or the standalone Workflows page.
Open a workflow containing an Update XM Directory Contacts task and click on it to open the configuration wizard.
You should land on the "Confirm import fields" screen with two columns showing Source Field and XM Directory Field.
Open the Browser Console
Right-click directly on the mapping table on any row where you can see a Source Field value.
Select Inspect or Inspect Element from the context menu.
In the developer tools panel that appears, click the Console tab.
Copy and Run the Extraction Script
Click the Copy Script button, paste into the console, then press Enter.
/**
* Qualtrics XM Directory Mapping Extractor (Contacts + Transactions)
* Extracts Source Field to XM Directory Field mappings - v2.4 (Resilient Edition)
* "Update XM Directory Contacts" workflow task.
* Run this script on EACH screen (Part 1 and Part 2).
* Developed by Pirai AI — piraiai.com
* Last updated: April 2026
*
* v2.4 CHANGE: Qualtrics regenerates hashed CSS classnames (e.g. "_2Oqzg") on each
* deployment. Row selection now uses stable attributes only (sourceFieldCell,
* textInput, role="combobox") instead of hashed row classnames, which were
* causing "0 rows found" errors after Qualtrics UI updates.
*/
(function() {
console.log('=== Qualtrics XM Directory Mapping Extractor Started ===');
function getRows(table) {
if (!table) return [];
// Resilient: any that contains a sourceFieldCell — avoids relying
// on hashed row classnames like "_2Oqzg" / "_l2NCb" which change between
// Qualtrics deployments.
const allRows = table.querySelectorAll('tbody tr');
return Array.from(allRows).filter(row => row.querySelector('td.sourceFieldCell'));
}
function extractContactMappings() {
const mappings = [];
const contactsTable = document.querySelector('.contactsDataMapper table.dataMapperTable');
if (!contactsTable) {
console.log('No contacts mapping table found');
return mappings;
}
const rows = getRows(contactsTable);
console.log(`\nFound ${rows.length} contact mapping rows`);
rows.forEach((row, index) => {
try {
let sourceField = '';
let xmDirectoryField = '';
const sourceInput = row.querySelector('td.sourceFieldCell input.textInput');
if (sourceInput) {
sourceField = sourceInput.value.trim();
}
const destinationInput = row.querySelector('input[role="combobox"]');
if (destinationInput) {
xmDirectoryField = destinationInput.value.trim();
}
if (sourceField || xmDirectoryField) {
mappings.push({
index: index + 1,
sourceField: sourceField,
xmDirectoryField: xmDirectoryField
});
}
} catch (error) {
console.warn(`Error processing contact row ${index}:`, error);
}
});
return mappings;
}
function extractTransactionMappings() {
const mappings = [];
const transactionTable = document.querySelector('.transactionDataMapper table.dataMapperTable');
if (!transactionTable) {
console.log('No transaction mapping table found');
return mappings;
}
const rows = getRows(transactionTable);
console.log(`\nFound ${rows.length} transaction mapping rows`);
rows.forEach((row, index) => {
try {
let sourceField = '';
let xmDirectoryField = '';
let makePipedText = false;
const sourceInput = row.querySelector('td.sourceFieldCell input.textInput');
if (sourceInput) {
sourceField = sourceInput.value.trim();
}
const secondColumn = row.querySelector('td:nth-child(2)');
if (secondColumn) {
const standaloneLabel = secondColumn.querySelector('label:not(:has(input))');
if (standaloneLabel) {
xmDirectoryField = standaloneLabel.textContent.trim();
} else {
const labelWithInput = secondColumn.querySelector('label input[type="text"]');
if (labelWithInput) {
xmDirectoryField = labelWithInput.value.trim();
} else {
const combobox = secondColumn.querySelector('input[role="combobox"]');
if (combobox) xmDirectoryField = combobox.value.trim();
}
}
}
const checkbox = row.querySelector('td:nth-child(3) input[type="checkbox"]');
if (checkbox) {
makePipedText = checkbox.checked;
}
if (sourceField || xmDirectoryField) {
mappings.push({
index: index + 1,
sourceField: sourceField,
xmDirectoryField: xmDirectoryField,
makePipedText: makePipedText ? 'Yes' : 'No'
});
}
} catch (error) {
console.warn(`Error processing transaction row ${index}:`, error);
}
});
return mappings;
}
function displayAsTable(mappings, type) {
console.log(`\n=== EXTRACTED ${type.toUpperCase()} MAPPINGS ===\n`);
console.table(mappings);
console.log(`\nTotal ${type} mappings: ${mappings.length}`);
}
function convertToCSV(mappings, includePipedText = false) {
if (mappings.length === 0) return '';
let headerRow = '"Index","Source Field","XM Directory Field"';
if (includePipedText) {
headerRow += ',"Make Piped Text"';
}
const dataRows = mappings.map(mapping => {
let row = [
`"${mapping.index}"`,
`"${mapping.sourceField.replace(/"/g, '""')}"`,
`"${mapping.xmDirectoryField.replace(/"/g, '""')}"`
];
if (includePipedText) {
row.push(`"${mapping.makePipedText}"`);
}
return row.join(',');
}).join('\n');
return headerRow + '\n' + dataRows;
}
function downloadCSV(csv, filename) {
const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
const link = document.createElement('a');
const url = URL.createObjectURL(blob);
link.setAttribute('href', url);
link.setAttribute('download', filename);
link.style.visibility = 'hidden';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(url);
console.log(`✓ Downloaded: ${filename}`);
}
function copyToClipboard(text) {
const textarea = document.createElement('textarea');
textarea.value = text;
textarea.style.position = 'fixed';
textarea.style.opacity = '0';
document.body.appendChild(textarea);
textarea.select();
try {
document.execCommand('copy');
console.log('✓ CSV data copied to clipboard!');
return true;
} catch (err) {
console.error('Failed to copy to clipboard:', err);
return false;
} finally {
document.body.removeChild(textarea);
}
}
console.log('Starting extraction...\n');
const contactMappings = extractContactMappings();
const transactionMappings = extractTransactionMappings();
if (contactMappings.length === 0 && transactionMappings.length === 0) {
console.error('❌ No mappings found! Make sure you are on the XM Directory mapping dialog.');
return;
}
if (contactMappings.length > 0) {
displayAsTable(contactMappings, 'contact');
}
if (transactionMappings.length > 0) {
displayAsTable(transactionMappings, 'transaction');
}
const contactCSV = convertToCSV(contactMappings, false);
const transactionCSV = convertToCSV(transactionMappings, true);
window.xmContactMappings = contactMappings;
window.xmTransactionMappings = transactionMappings;
window.xmContactCSV = contactCSV;
window.xmTransactionCSV = transactionCSV;
window.downloadContactMappingsCSV = function(filename) {
downloadCSV(contactCSV, filename || 'xm_contact_mappings.csv');
};
window.copyContactMappingsCSV = function() {
return copyToClipboard(contactCSV);
};
window.downloadTransactionMappingsCSV = function(filename) {
downloadCSV(transactionCSV, filename || 'xm_transaction_mappings.csv');
};
window.copyTransactionMappingsCSV = function() {
return copyToClipboard(transactionCSV);
};
window.downloadAllMappingsCSV = function() {
if (contactMappings.length > 0) {
downloadCSV(contactCSV, 'xm_contact_mappings.csv');
}
if (transactionMappings.length > 0) {
downloadCSV(transactionCSV, 'xm_transaction_mappings.csv');
}
};
window.getContactJSON = function() {
return JSON.stringify(contactMappings, null, 2);
};
window.getTransactionJSON = function() {
return JSON.stringify(transactionMappings, null, 2);
};
console.log('\n=== ACTIONS AVAILABLE ===');
console.log('CONTACT MAPPINGS:');
console.log(' 1. Download CSV: downloadContactMappingsCSV()');
console.log(' 2. Copy CSV: copyContactMappingsCSV()');
console.log(' 3. View JSON: getContactJSON()');
console.log('\nTRANSACTION MAPPINGS:');
console.log(' 4. Download CSV: downloadTransactionMappingsCSV()');
console.log(' 5. Copy CSV: copyTransactionMappingsCSV()');
console.log(' 6. View JSON: getTransactionJSON()');
console.log('\nALL MAPPINGS:');
console.log(' 7. Download All: downloadAllMappingsCSV()');
console.log(' 8. View data: xmContactMappings / xmTransactionMappings');
console.log('\n✓ Extraction complete! Use the commands above to export the data.');
})();
4
Export Contact Mappings
You should see the contact mappings table printed in the console. Run this command to download:
downloadContactMappingsCSV()
// downloads xm_contact_mappings.csv
You should see: ✓ Downloaded: xm_contact_mappings.csv
Keep the console and the Qualtrics dialog open, you need both for Part 2.
5
Click "Next" in Qualtrics
Click the Next button at the bottom of the contact mapping screen to advance to the transaction data screen. Stay inside the task dialog.
Part 2: Extract Transaction Mappings
6
Enable the Transaction Data Checkbox
On the "Map specific values (optional)" screen, check the Transaction data checkbox to reveal the transaction mapping table.
You should now see three columns: Source Field, XM Directory Field, and Make Piped Text.
How to confirm you're on the right screen: Look for a "Transaction data" checkbox, a "Make piped text" column header, and a Save button at the bottom (not Next).
7
Run the Same Script Again
Paste and run the exact same script from Step 3 into the console again. This time it will find the transaction mapping table and extract those rows automatically.
Yes, the same script. It detects which screen you are on and extracts accordingly. The contact table and transaction table are in different parts of the page structure, which is why a second run is needed.
8
Export Transaction Mappings
Run this command to download your transaction mappings:
downloadTransactionMappingsCSV()
// downloads xm_transaction_mappings.csv
Or download both files at once if you prefer:
downloadAllMappingsCSV()
// downloads both CSV files in one command
Done. You now have two CSV files with complete documentation of your XM Directory workflow mappings.
Understanding Your Output
Contact Mappings (xm_contact_mappings.csv)
Extracted from the "Confirm import fields" screen. Shows which data source fields map to which XM Directory contact fields.
Index Source Field XM Directory Field
1 ${e://Field/SampleField3} First name
2 ${e://Field/SampleField4} Last name
3 ${e://Field/SampleField5} Email
4 ${e://Field/SampleField6} Phone number
5 ${e://Field/SampleField2} Contact ID
Transaction Mappings (xm_transaction_mappings.csv)
Extracted from the "Map specific values" screen. Includes the Make Piped Text column, which is critical for downstream workflow logic.
Index Source Field XM Directory Field Make Piped Text
1 ${e://Field/purchase_date} Transaction Date No
2 ${e://Field/product_name} product_name Yes
3 ${e://Field/order_total} order_value Yes
4 ${e://Field/order_status} status No
Why "Make Piped Text" matters
When a transaction field is marked Yes, it becomes available as ${tr://Field/field_name} in all subsequent workflow tasks including email personalisation, conditional branches, web service calls. If a downstream task is failing unexpectedly, check this column first. A field used in an email template that was not marked Make Piped Text will silently fail.
Comparing Across Environments (Dev, Test, and Prod)
One of the most powerful use cases for these CSV exports is comparing XM Directory Contacts task configurations across Qualtrics environments before deployment. Configuration drift between Dev, Test, and Prod is one of the most common causes of workflow failures that are difficult to diagnose.
1
Extract from Development Environment
Run both scripts in your Dev environment and download both CSVs. Save them as xm_contact_mappings_DEV.csv and xm_transaction_mappings_DEV.csv.
2
Extract from Test Environment
Repeat the process in Test and save as xm_contact_mappings_TEST.csv and xm_transaction_mappings_TEST.csv.
3
Extract from Production Environment
Extract from Prod and save as xm_contact_mappings_PROD.csv and xm_transaction_mappings_PROD.csv.
4
Compare with Pirai AI CSV Comparator
Upload two CSV files to the Pirai AI CSV Comparator to instantly identify mismatches. The tool shows differences row by row so you can spot missing fields, Make Piped Text status changes, XM Directory field name discrepancies, and source field mismatches without needing Excel or any external service. Your data stays in the browser.
Common configuration drift patterns
- Missing contact fields : a source field mapped in Dev but absent in Prod
- Make Piped Text changes : a transaction field marked Yes in Dev but No in Prod, breaking downstream email personalisation
- XM Directory field name discrepancies : field renamed between environments without documentation
- Source field name differences : casing or piped text syntax differences between environments
- Index order differences : fields in a different sequence, which can affect downstream processing
Troubleshooting
No mappings found
- Confirm you are inside the "Update XM Directory Contacts" task configuration with the mapping table fully visible
- Scroll through the table to ensure all rows have loaded before running the script
- Refresh the page, reopen the task, and try again
No transaction mappings found (most common issue)
- You ran the script on the contact screen only. Click Next, check the Transaction data checkbox, and run the script again
- Make sure the Transaction data checkbox is ticked before running on Part 2
- If your workflow has no transaction data configured, this is expected and not an error
Download not working
- Use the clipboard alternative:
copyContactMappingsCSV() then paste into Excel or Google Sheets
- Check your browser is not blocking downloads from qualtrics.com
- Disable any pop-up blocker temporarily and retry
Script shows errors or runs but finds nothing
- Make sure you copied the entire script, it is long, use Ctrl+A inside the code block before copying
- Type
clear() in the console to reset it, then paste and run again
- Try Chrome if you are using another browser
Advanced Usage
Custom export filenames
Pass a filename to keep your exports organised by workflow, environment and date:
downloadContactMappingsCSV('PostPurchase_Contacts_2026-03-06.csv')
downloadTransactionMappingsCSV('PostPurchase_Transactions_2026-03-06.csv')
Recommended naming pattern: {WorkflowName}_{Type}_{YYYY-MM-DD}.csv
Filter and analyse data in the console
After extraction the data is stored as JavaScript arrays you can query directly:
// Only fields marked for piped text
xmTransactionMappings.filter(m => m.makePipedText === 'Yes')
// Find a specific contact field
xmContactMappings.find(m => m.xmDirectoryField === 'Email')
// Count totals
console.log(xmContactMappings.length, xmTransactionMappings.length)
Export as JSON for programmatic use
If you need the data in JSON format for documentation pipelines, validation scripts or CI/CD workflows:
// View JSON in console
console.log(JSON.stringify(xmContactMappings, null, 2))
// Download as JSON file
const b = new Blob([JSON.stringify(xmContactMappings, null, 2)], {type:'application/json'});
const a = document.createElement('a');
a.href = URL.createObjectURL(b);
a.download = 'contact_mappings.json'; a.click();
Best practices for documentation and versioning
A few habits that pay off when workflows change or environments are migrated:
- Extract before making any changes, which creates a clean rollback reference
- Use a consistent folder structure:
WorkflowDocs / 2026-Q1 / WorkflowName_Type_Date.csv
- For environment migrations, extract from test first, verify all source fields exist in production, reconfigure, then extract again and compare to confirm accuracy
- Use Excel VLOOKUP to diff two extractions:
=IF(VLOOKUP(B2,Sheet2!B:C,2,FALSE)=C2,"Match","Different")
Need to convert surveys into Qualtrics?
This tool documents your XM Directory workflow mappings. If you also need to convert Word, PDF or Excel questionnaires into QSF files for Qualtrics import, Pirai AI handles that automatically across 20+ survey platforms with no manual scripting required.