Custom Backend Integration

This guide outlines how to implement a custom preference centre UI using an API integration with the DataGuard CPM platform. This custom integration allows you to easily render a preference centre in iOS, Android, Web, or any other mobile or desktop technology. By leveraging the same Template technology as the widget, your non-technical staff can update text, Permissions, and Preferences without requiring code changes.

The example provided uses JavaScript, but any programming language can be utilised.

Prerequisites

Before starting, ensure you have a Template set up. A Template specifies the Permissions and Preferences to be rendered and the order in which they appear. Additionally, a Citizen must already exist in your system.

  • Use the admin UI to create a Template that contains the necessary Permissions and Preferences for display in the custom UI.
  • The same Template can be used across custom integrations and the web widget, ensuring consistency across web, mobile, and other platforms.
  • Any changes made to the Template in the UI will be immediately reflected across all capture points using this Template.

Collect the Required Configuration

This guide will use the DataGuard CPM API, with the URL varying based on your environment:

EnvironmentPlatform URL
Sandboxhttps://sandbox-api.consentric.io
Production EUhttps://api.dgconsent.de
Production UKhttps://api.consentric.io

If you're unsure which environment you're using, please contact support.

You'll also need your applicationId, the templateId from the previous step, and an API Key. Refer to the API Authentication page for more information on API Keys.

Assign the configuration details to constants in your application so you can reference them later:

const PLATFORM_URL = 'https://api.consentric.io';
const APPLICATION_ID = '<app-id>';
const TEMPLATE_ID = '<template-id>';
const API_KEY = '<api-key>';

Step 1: Retrieve Current State

Next, use the API to retrieve the Template created earlier. The Template will be merged with the Citizen's current permission and preference state, creating an "enriched Template" ready for rendering.

  • externalRef: A unique identifier for a Citizen (e.g., the user ID in your system). If the Citizen does not exist, this parameter can be omitted, and a Template with default state will be returned.

Refer to the API Reference for full documentation on this endpoint.

const currentState = await fetch(
    `${PLATFORM_URL}/v1/consent-state?applicationId=${APPLICATION_ID}&templateId=${TEMPLATE_ID}&externalRef=<citizen-external-reference>`,
    {
        headers: {
            'X-Api-Key': API_KEY,
        },
    },
).then((response) => response.json());

Note: This request must be made on your backend, with the data then sent to the frontend responsible for rendering the content. Any request to the DataGuard API that requires authentication must be made on the backend.

Step 2: Render the Capture Point

The response can be used directly to render the capture point. If the backend is not responsible for rendering the application, this object should first be transferred to the frontend as-is.

A Template consists of multiple "blocks," each with a different "type" that requires different rendering logic. Render the blocks in order, delegating the rendering for each type to the appropriate function:

const CapturePoint = ({ template }) =>
    template.blocks.map((block) => {
        switch (block.type) {
            case 'permissions':
                return <Permissions permissionsBlock={block} />;
            case 'single-choice-preference':
                return <SingleChoicePreference preference={block} />;
            case 'multi-choice-preference':
                return <MultiChoicePreference preference={block} />;
            case 'text':
                return <Text textBlock={block} />;
            default:
                // Do not throw an error if the block type is unrecognised.
                // New block types may be added in the future.
                return null;
        }
    });

Step 3: Render Permissions

The following example demonstrates how to render a permissions block.

Replace the "RenderHtml" component with sanitised render functionality from your framework, and update the "onChange" callback with a call to your state management framework:

const Permissions = ({ permissionsBlock }) => (
    <div>
        <RenderHtml html={permissionsBlock.statement.text} />
        {permissionsBlock.options.map((option) => {
            const id = `option-${option.optionId}`;
            return (
                <div>
                    <input
                        type="checkbox"
                        id={id}
                        checked={option.selected}
                        onChange={(event) =>
                            (option.selected = event.target.checked)
                        }
                    />
                    <label htmlFor={id}>{option.label}</label>
                </div>
            );
        })}
    </div>
);

Step 4: Render Single Choice Preferences

Single choice preferences allow only one value to be selected and can be rendered as radio buttons or a dropdown menu. In this example, radio buttons are used.

Replace the "onClick" callback with a call to your state management framework:

const SingleChoicePreference = ({ preference }) => (
    <div>
        <h3>{preference.title}</h3>
        {preference.choices.map((choice) => {
            const id = `preference-${preference.reference}-${choice.reference}`;
            return (
                <div>
                    <input
                        type="radio"
                        id={id}
                        checked={preference.selectedChoice === choice.reference}
                        onClick={() =>
                            (preference.selectedChoice = choice.reference)
                        }
                    />
                    <label htmlFor={id}>{choice.label}</label>
                </div>
            );
        })}
    </div>
);

Step 5: Render Multi-Choice Preferences

Multi-choice preferences allow zero or more choices to be selected and can be rendered as checkboxes or a multiselect dropdown. The example below uses checkboxes.

Replace the "onChange" callback with a call to your state management framework:

const MultiChoicePreference = ({ preference }) => (
    <div>
        <h3>{preference.title}</h3>
        {preference.choices.map((choice) => {
            const id = `preference-${preference.reference}-${choice.reference}`;
            return (
                <div>
                    <input
                        type="checkbox"
                        id={id}
                        checked={choice.selected}
                        onChange={(event) =>
                            (choice.selected = event.target.checked)
                        }
                    />
                    <label htmlFor={id}>{choice.label}</label>
                </div>
            );
        })}
    </div>
);

Step 6: Render Text

A text block is a static HTML string that should be rendered as-is.

Replace the "RenderHtml" component with sanitised render functionality from your framework:

const Text = ({ textBlock }) => <RenderHtml html={textBlock.data} />;

Step 7: Submit Updated State

When the user submits the form, if the enriched Template object has been kept up-to-date as the user interacted with it, it can be directly submitted to the endpoint shown below. Otherwise, update it with the current state before submission.

If the request returns a 200 response code, the Citizen’s Permissions and Preferences will be saved and synchronised across any other systems integrated with the platform.

Ensure that the entire enriched Template object is mutated and sent to the submission endpoint, as it contains additional metadata required to process the request correctly.

Additionally, if the original GET request didn’t contain the externalRef, add this field to the request body before submission.

The externalRef can represent either an existing Citizen or a new one. If the Citizen doesn’t already exist, they will be created as part of the request.

Refer to the API Reference for full documentation on this endpoint.

await fetch(`${PLATFORM_URL}/v1/consent-state`, {
    method: 'POST',
    headers: {
        'content-type': 'application/json',
        authorization: `Bearer ${jwt}`,
    },
    body: JSON.stringify(template),
}).then((response) => response.json());