Import content

Introduction

Goal

Migrate content stored in a different CMS to Bloomreach Content using the Content Batch Import API.

Background

When coming from a different CMS, a lot of content might need to be migrated into Bloomreach Content.

Our goal is to support this use case and make it as easy as possible for developers to quickly migrate into Bloomreach Content.

We solve the migration of data problem by offering a Content Batch Import API. It enables developers to import large amounts of content into a Bloomreach project.

In this tutorial, we'll walk you through the process step by step with examples showing how to import content into Bloomreach Content. You can import both documents and/or pages in the batch request.

Prerequisites

Before starting:

To make the API requests in this tutorial, we recommend using the Postman collection to make the API requests. However, you can use any other method or tool you like such as curl or httpies.

Step by step tutorial

1. Convert your content to our format

The batch import works by uploading a JSON lines file, also known as an NDJSON or new line-delimited JSON file. Each line of the file contains a JSON object representing a single document or page, in the same format used by the Content Management API.

You can follow our detailed Recipe on what each field means in the batch import format:

In case you just want to see it working for yourself and quickly try out with some dummy content, consider the following example (here represented as a regular JSON array for readability) for a channel named "my-channel":

[
{
    "type": "document",
    "contentType": "brxsaas:banner",
    "fields": [
        {
            "name": "title",
            "value": [
                "Our team is ready for your next product"
            ]
        },
        {
            "name": "content",
            "value": [
                "<p>example content</p>"
            ]
        },
        {
            "name": "image",
            "value": [
                "/"
            ]
        },
        {
            "name": "cta",
            "value": [
                "Start your next project"
            ]
        },
        {
            "name": "link",
            "value": [
                "/content/documents/my-channel/pages/products/all"
            ]
        }
    ],
    "name": "next-project11",
    "displayName": "Next Project11",
    "path": "/content/documents/my-channel/banners/next-project11"
},
{
    "type": "document",
    "contentType": "brxsaas:banner",
    "fields": [
        {
            "name": "title",
            "value": [
                "Brand 1"
            ]
        },
        {
            "name": "content",
            "value": [
                "<p>Sample content</p>"
            ]
        },
        {
            "name": "image",
            "value": [
                "/content/gallery/my-channel/banners/brand-1.jpg"
            ]
        },
        {
            "name": "cta",
            "value": []
        },
        {
            "name": "link",
            "value": [
                "/content/documents/my-channel/pages/products/all"
            ]
        }
    ],
    "name": "brand-111",
    "displayName": "Brand 111",
    "path": "/content/documents/my-channel/banners/brand-111"
},
{
    "type": "page",
    "relativePath": "pages/home-222",
    "channelId": "my-channel",
    "name": "home-222",
    "displayName": "Home 222",
    "layout": "two-column",
    "document": {
        "contentType": "brxsaas:content",
        "fields": [
            {
                "name": "title",
                "value": [
                    "My page"
                ]
            },
            {
                "name": "introduction",
                "value": [
                    "Sample introduction"
                ]
            },
            {
                "name": "content",
                "value": [
                    "Example page content"
                ]
            },
            {
                "name": "image",
                "value": [
                    "/"
                ]
            },
            {
                "name": "date",
                "value": []
            }
        ]
    },
    "containers": [
        {
            "path": "top",
            "components": [
                {
                    "componentDefinition": "brx-reference-spa/referencespa-single-banner-carousel",
                    "componentConfigurations": [
                        {
                            "id": "DEFAULT",
                            "content": null,
                            "parameters": [
                                {
                                    "name": "alignment",
                                    "value": "center"
                                },
                                {
                                    "name": "document1",
                                    "value": "banners/safe-workspace-1"
                                },
                                {
                                    "name": "document2",
                                    "value": "banners/safe-workspace-2"
                                },
                                {
                                    "name": "interval",
                                    "value": "10000"
                                }
                            ]
                        }
                    ]
                }
            ]
        },
        {
            "path": "main",
            "components": [
                {
                    "componentDefinition": "brx-reference-spa/referencespa-titleandtext",
                    "componentConfigurations": [
                        {
                            "id": "DEFAULT",
                            "content": {
                                "contentType": "titleandtext",
                                "fields": [
                                    {
                                        "name": "title",
                                        "value": [
                                            "Welcome to brX ContentX"
                                        ]
                                    },
                                    {
                                        "name": "text",
                                        "value": [
                                            "Welcome to the Bloomreach Sample Front-end Application for the brX Content."
                                        ]
                                    }
                                ]
                            },
                            "parameters": [
                                {
                                    "name": "titlesize",
                                    "value": "H3"
                                },
                                {
                                    "name": "textalignment",
                                    "value": "left"
                                },
                                {
                                    "name": "style",
                                    "value": "style1"
                                }
                            ]
                        }
                    ]
                },
                {
                    "componentDefinition": "brx-reference-spa/referencespa-titleandtext",
                    "componentConfigurations": [
                        {
                            "id": "DEFAULT",
                            "content": {
                                "contentType": "titleandtext",
                                "fields": [
                                    {
                                        "name": "title",
                                        "value": [
                                            ""
                                        ]
                                    },
                                    {
                                        "name": "text",
                                        "value": [
                                            "We have tried to keep it as clean, effective and simple as possible"
                                        ]
                                    }
                                ]
                            },
                            "parameters": [
                                {
                                    "name": "titlesize",
                                    "value": "H3"
                                },
                                {
                                    "name": "textalignment",
                                    "value": "left"
                                },
                                {
                                    "name": "style",
                                    "value": "style1"
                                }
                            ]
                        }
                    ]
                },
                {
                    "componentDefinition": "brx-reference-spa/referencespa-category-highlight",
                    "componentConfigurations": [
                        {
                            "id": "DEFAULT",
                            "content": {
                                "contentType": "CategoryHighlight",
                                "fields": [
                                    {
                                        "name": "title",
                                        "value": [
                                            "Highlight categories"
                                        ]
                                    },
                                    {
                                        "name": "connectorid",
                                        "value": [
                                            "brsm"
                                        ]
                                    },
                                    {
                                        "name": "CommerceCategoryCompound",
                                        "value": [
                                            {
                                                "fields": {
                                                    "categoryid": [
                                                        "PNB160400000000"
                                                    ]
                                                }
                                            },
                                            {
                                                "fields": {
                                                    "categoryid": [
                                                        "PNB160402010000"
                                                    ]
                                                }
                                            },
                                            {
                                                "fields": {
                                                    "categoryid": [
                                                        "PNB160401010000"
                                                    ]
                                                }
                                            },
                                            {
                                                "fields": {
                                                    "categoryid": [
                                                        "PNB250800000000"
                                                    ]
                                                }
                                            }
                                        ]
                                    }
                                ]
                            },
                            "parameters": []
                        }
                    ]
                }
            ]
        }
    ]
}
]

When converted to NDJSON (for example using this JSON to NDJSON Online Converter) it looks like this:

{"type":"document","contentType":"brxsaas:banner","fields":[{"name":"title","value":["Our team is ready for your next product"]},{"name":"content","value":["<p>example content</p>"]},{"name":"image","value":["/"]},{"name":"cta","value":["Start your next project"]},{"name":"link","value":["/content/documents/my-channel/pages/products/all"]}],"name":"next-project11","displayName":"Next Project11","path":"/content/documents/my-channel/banners/next-project11"}
{"type":"document","contentType":"brxsaas:banner","fields":[{"name":"title","value":["Brand 1"]},{"name":"content","value":["<p>Sample content</p>"]},{"name":"image","value":["/content/gallery/my-channel/banners/brand-1.jpg"]},{"name":"cta","value":[]},{"name":"link","value":["/content/documents/my-channel/pages/products/all"]}],"name":"brand-111","displayName":"Brand 111","path":"/content/documents/my-channel/banners/brand-111"}
{"type":"page","relativePath":"pages/home-222","channelId":"my-channel","name":"home-222","displayName":"Home 222","layout":"two-column","document":{"contentType":"brxsaas:content","fields":[{"name":"title","value":["My page"]},{"name":"introduction","value":["Sample introduction"]},{"name":"content","value":["Example page content"]},{"name":"image","value":["/"]},{"name":"date","value":[]}]},"containers":[{"path":"top","components":[{"componentDefinition":"brx-reference-spa/referencespa-single-banner-carousel","componentConfigurations":[{"id":"DEFAULT","content":null,"parameters":[{"name":"alignment","value":"center"},{"name":"document1","value":"banners/safe-workspace-1"},{"name":"document2","value":"banners/safe-workspace-2"},{"name":"interval","value":"10000"}]}]}]},{"path":"main","components":[{"componentDefinition":"brx-reference-spa/referencespa-titleandtext","componentConfigurations":[{"id":"DEFAULT","content":{"contentType":"titleandtext","fields":[{"name":"title","value":["Welcome to brX ContentX"]},{"name":"text","value":["Welcome to the Bloomreach Sample Front-end Application for the brX Content."]}]},"parameters":[{"name":"titlesize","value":"H3"},{"name":"textalignment","value":"left"},{"name":"style","value":"style1"}]}]},{"componentDefinition":"brx-reference-spa/referencespa-titleandtext","componentConfigurations":[{"id":"DEFAULT","content":{"contentType":"titleandtext","fields":[{"name":"title","value":[""]},{"name":"text","value":["We have tried to keep it as clean, effective and simple as possible"]}]},"parameters":[{"name":"titlesize","value":"H3"},{"name":"textalignment","value":"left"},{"name":"style","value":"style1"}]}]},{"componentDefinition":"brx-reference-spa/referencespa-category-highlight","componentConfigurations":[{"id":"DEFAULT","content":{"contentType":"CategoryHighlight","fields":[{"name":"title","value":["Highlight categories"]},{"name":"connectorid","value":["brsm"]},{"name":"CommerceCategoryCompound","value":[{"fields":{"categoryid":["PNB160400000000"]}},{"fields":{"categoryid":["PNB160402010000"]}},{"fields":{"categoryid":["PNB160401010000"]}},{"fields":{"categoryid":["PNB250800000000"]}}]}]},"parameters":[]}]}]}]}

Save the above NDJSON data to a file, for example content.ndjson.

2. Create a development project

The content must be imported into a specific development project. This constraint is to guarantee that all operations are performed without having any chances of affecting the live website, since all write operations are performed on the unpublished variant of a page or document associated with the development project.

Therefore the first step is to create a development project and add your channel to the project. You can do this using the Projects app in the UI or using the Management APIs.

To create a new development project, use a POST request to the Project Management API's Project endpoint:

POST https://<your-content-environment>.bloomreach.io/management/projects/v1/

Use the following JSON payload:

{
    "name": "content-import-project",
    "includeContentTypes": false,
    "description": "Content Import Project"
}

You should receive a 201 response with a body similar to the following:

{
    "id": "vTnTj",
    "name": "content-import-project",
    "includeContentTypes": false,
    "description": "Content Import Project",
    "state": {
        "status": "IN_PROGRESS",
        "message": "In progress",
        "errors": null,
        "availableActions": []
    },
    "items": null,
    "system": {
        "createdBy": "[email protected]",
        "createdAt": "2023-02-13T19:32:44.968+01:00",
        "updatedBy": "[email protected]",
        "updatedAt": "2023-02-13T19:32:44.968+01:00",
        "mergedBy": null,
        "mergedAt": null
    }
}

Note the project ID (vTnTj in the example above), you'll need it in the next steps.

Now add your channel to the project using the Site Management API's Channels endpoint:

POST https://<your-content-environment>.bloomreach.io/management/site/v1/channels/

Use the following JSON payload, substituting in the IDs of your project and your channel:

{
    "branch": "vTnTj",
    "branchOf": "my-channel"
}

You'll need the project ID for the actual content import. If you used to UI to create the project and add your channel, you can retrieve the project ID (for example vTnTj) in the Projects app, the Site development app, or the Site Management API.

In the latter case, use the endpoint Get all channels.

{
  ...,
  "branch": "vTnTj",
  ...
}

The channel's branch property contains the project ID.

3. Import content into the development project

Send a POST request to the Content Batch Import API's Create content endpoint, uploading the previously saved NDJSON file as body:

POST https://<your-content-environment>.bloomreach.io/management/content-import/v1/project/vTnTj

(Make sure to substitute your project ID)

When sending the content, no validation is performed against the content model.

You'll receive a response similar to the following:

{
    "operationId": "8fd2a4b7-7df1-4b6e-b2f6-25d9e5af66a2",
    "projectId": "vTnTj",
    "status": "STARTING",
    "exitMessage": "",
    "readCount": 0,
    "writeCount": 0,
    "skipCount": 0,
    "startTime": null,
    "endTime": null,
    "errorLog": []
}

Note the operationId, you'll need this in the next step.

4. Check the status of the import via API

You can retrieve a list of all import operations via List all operations. This will return a list of IDs that represent the jobs that are running

Then, you can get the details of each of the jobs using the Get operation details endpoint, substituting in your import operation's ID:

GET https://<your-content-environment>.bloomreach.io/management/content-import/v1/operations/8fd2a4b7-7df1-4b6e-b2f6-25d9e5af66a2

You should receive a response similar to the one below. If there were any errors, they are listed in the errorLog array.

{
  "operationId": "8fd2a4b7-7df1-4b6e-b2f6-25d9e5af66a2",
  "projectId": "vI8Xo",
  "status": "COMPLETED",
  "readCount": 6,
  "writeCount": 5,
  "skipCount": 1,
  "startTime": "2022-03-21@10:47:00.448+0000",
  "endTime": "2022-03-21@10:47:08.632+0000",
  "errorLog": [
    {
      "path": "pages/home",
      "error": "Item not found; nested exception is javax.jcr.ItemNotFoundException: Component definition 'hst:components/sample/single-banner-carouselZ' not found"
    }
  ]
}

5. Check the imported content in the UI

Using the Projects app, you can preview the imported pages and documents in the development project and approve them so that a merge can be done.

6. Merge the project

When merging the development project, all the imported content will be published into Core.

You can also use the Project Management API to approve all changes and merge the project in a single request:

POST https://<your-content-environment>.bloomreach.io/management/projects/v1/vTnTj:merge

Use the following JSON payload:

{
    "approveAllChanges": true
}

Error handling

In case something goes wrong during the batch import process, there is the option of deleting the project before it's merged and starting over from scratch in a new development project.