Building a CSV import system for SitecoreAI
Learn how to build a self-contained Next.js application for importing CSV data into SitecoreAI using the Authoring GraphQL API.
Learn how to build a self-contained Next.js application for importing CSV data into SitecoreAI using the Authoring GraphQL API.
Start typing to search...
Many organizations manage hundreds of content items annually. Teams often receive data in CSV format from various sources, but getting this data into SitecoreAI was a manual, time-consuming process involving:
You end up with hours of manual work, prone to human error and just frustrations from content editors.
Sitecore has made efforts into creating work arounds where you can create your own script in order to deal with these issues. We decided to take a step further and solve this with the importance of being user-friendly. We decided to build a web application that content editors can use directly.
The import process follows this workflow:
The system uses Sitecore's Authoring GraphQL API to create and update items. The process is split into two steps for reliability.
mutation CreateItem(
$name: String!
$templateId: ID!
$parent: ID!
$language: String!
) {
createItem(
input: {
name: $name
templateId: $templateId
parent: $parent
language: $language
}
) {
item {
itemId
name
path
}
}
}Important Notes:
parent parameter requires a GUID (not a path) - query for parent ID firsttemplateId uses your custom template GUIDmutation {
updateItem(
input: {
itemId: "{GUID}"
database: "master"
language: "en"
version: 1
fields: [
{ name: "title", value: "Example Title", reset: false }
{ name: "startDateTime", value: "2026-07-01T11:00:00", reset: false }
]
}
) {
item {
itemId
name
}
}
}Important Notes:
database: "master" parameterreset: false for each field to preserve existing dataHere are some things we've taken note of which plays a big role in preventing any side effects and keeping the flow of the application seamless.
Running the same import twice shouldn't create duplicate items. This three-layer system prevents that:
// Check cache first
let existingId = itemIdCache.get(fullItemPath);
if (!existingId) {
// Not in cache, check Sitecore directly
try {
existingId = await getItemIdByPath(fullItemPath, accessToken);
if (existingId) {
itemIdCache.set(fullItemPath, existingId); // Cache it
}
} catch (error) {
// Item doesn't exist - we'll create it
}
}
// If exists, update instead of create
if (existingId) {
await updateItemFields(existingId, fieldsToUpdate, accessToken);
return { id: existingId, path: fullItemPath, name: itemName };
}This approach:
Items often need to be organized in folder hierarchies. This recursive function creates the entire path automatically:
async function getOrCreateParentId(itemPath: string, accessToken: string) {
// Try to get existing item
try {
return await getItemIdByPath(itemPath, accessToken);
} catch (error) {
// Doesn't exist - create it
const folderName = pathParts[pathParts.length - 1];
const parentPath = pathParts.slice(0, -1).join('/');
// Recursively ensure parent exists
const parentId = await getOrCreateParentId(parentPath, accessToken);
// Create this folder
return await createFolder(parentPath, folderName, accessToken);
}
}Example: Creating an item at /sitecore/content/YourSite/Events/2026/July/event-name will automatically create Events/, 2026/, and July/ folders if they don't exist.
Multiple items with the same title need unique item names in Sitecore. This function generates URL-safe names with identifiers:
function generateItemName(title: string, uniqueIdentifier?: string): string {
let itemName = title
.toLowerCase()
.replace(/[^a-z0-9\s-]/g, '')
.replace(/\s+/g, '-')
.replace(/-+/g, '-')
.replace(/^-|-$/g, '');
if (uniqueIdentifier) {
// Add unique identifier (could be date, ID, etc.)
itemName += `-${uniqueIdentifier}`;
}
return itemName;
}Example: "Summer Festival" on July 1, 2026 becomes summer-festival-2026-07-01 This ensures:
Here are some configurations you will have to do in order for the web application to work.
In our queries above you'll see we didn't have too many fields to map, be sure to take note of the fields in the CSV that you wish to populate into sitecore but creating your templates correctly.
In order for your application to work with the Sitecore Authoring GraphQL you will need to do some configurations.
Environment Variables:
SITECORE_CLIENT_ID=your-client-id
SITECORE_CLIENT_SECRET=your-client-secret
SITECORE_AUTHORING_ENDPOINT=https://your-instance.sitecorecloud.io/sitecore/api/authoring/graphql/v1Sitecore Requirements:
xmcloud.item.createxmcloud.item.updatexmcloud.item.read/sitecore/content/YourSite/Content)Based on how we were able to create the application, follow these practices:
This CSV import pattern is suitable for:
This application is a standalone application catered to import data from a CSV. It lives separately from the Sitecore environment which may be an added tool your team needs to maintain and keep a track of. To solve this problem Sitecore has introduced the Marketplace, integrating the same methodology and behavior into the Marketplace setup will help keep this tool within Sitecore and help keep it secure.