Integrate Typeform in Bloomreach Engagement using Omniconnect! This integration takes submissions from Typeform forms and records them into Bloomreach as survey events.

Use cases

This integration can be used in multiple ways, depending on the data captured. For example:

  • Zero-party data capture
  • NPS

There is no limit on the data that can be captured. Therefore, it can be used instead of Bloomreach surveys, and the use cases are similar.

How to set it up

🚧

Prerequisites

  • A Bloomreach Engagement project with integration access
  • A Typeform account
  • A form with at least one question that collects customer's IDs
  • Limited JavaScript knowledge

1. Create the integration

  1. In Bloomreach Engagement, go to Data & Assets > Integrations > + Add new integration
  1. Find Omniconnect and click on + Add integration
  2. Rename the integration and click on Save changes
  3. Go to the Transformation tab
  4. Paste the transformation function into the appropriate text field

2. Set up a webhook in Typeform

  1. Go back to the Settings tab and copy the Omniconnect URL
  2. Go to Typeform and navigate to the form you want to share
  3. Go to Connect > Webhooks > Add a webhook
  1. Paste the Omniconnect URL (Webhook URL) and click on Save webhook
  2. Go to View deliveries > Send test request
  3. Make a note of the customer ID

📘

For more information, visit the Typeform documentation

3. Configure the transformation function

The transformation function declares 2 variables. Update these accordingly.

idKey

idKey refers to the name/key of the ID that contains the ID you will use for mapping, usually an email address. The default value is registered. registered is advised wherever possible.

idQuestions

idQuestions refers to a list of the question/answer IDs from the previous step. By default, Typeform forms can be created without any IDs, in which case Bloomreach would not be able to process and store these forms. However, if a question within the form collects the customer's email, this can be used to identify the customer.

idQuestions essentially requests a list of IDs from the forms and includes the specific email for customer identification. The first email input field will be used if this list is empty. If even this is not present, an error will appear.

The last step should have already populated the input with a test payload. You can now transform the input to check the result. Click on Test transformation to transform the input.

Transformation function

The function creates 1 event for the submission and 1 event for each question/answer. It then returns 1 survey event for each answer.

/**
 * Params to be set to allow customization
 * @param {Array<string>} idQuestions - List of question ids where id is stored to use for customer identification
 * @param {string} idKey - Field id where id is stored
 */
const idQuestions = ["OyreMH40gpaO"];
const idKey = "registered";

/**
 * Handler is the entry point for the function that enables the transformation of the data.
 * @param {object} data - The input data
 * @returns {Array<object>} - Array of transformed events
 */
function handler(data) {
    const response = [];
    const { form_response: formResponse } = data;
    const timestamp = getTimestamp(formResponse.submitted_at);
    const idValue = getIdValue(formResponse.answers);
    

    const customerIds = {
        [idKey]: idValue
    };

    response.push(returnEvent(getEventProperties(data, "submission"), customerIds, timestamp));

    formResponse.definition.fields.slice(0, 50).forEach((field, index) => {
        const answer = processAnswer(formResponse.answers[index]);
        const properties = {
            ...getEventProperties(data, "answer"),
            question: field.title,
            question_id: field.id,
            question_type: field.type,
            question_index: index,
            answer_type: formResponse.answers[index].type,
            answer
        };
        response.push(returnEvent(properties, customerIds, timestamp));
    });

    return response;
}

/**
 * Extracts id from the form response answers
 * @param {Array<object>} answers - The answers from the form response
 * @returns {string | undefined} - The id or undefined if not found
 */
function getIdValue(answers) {
    const idAnswer = answers.find(obj => idQuestions.includes(obj.field.id));
    return idAnswer?.email || answers.find(obj => obj.type === 'email')?.email;
}

/**
 * Process the answer based on its type.
 * @param {object} answer - The answer object
 * @returns {*} - Processed answer
 */
function processAnswer(answer) {
    switch (answer.type) {
        case 'date':
            return getMiddayUtcTimestamp(answer.date);
        case 'choice':
            return answer.choice.label;
        case 'choices':
            return answer.choices.labels;
        default:
            return answer[answer.type];
    }
}

/**
 * Get the properties for an event.
 * @param {object} data - The input data
 * @param {string} action - The action type
 * @returns {object} - Event properties
 */
function getEventProperties(data, action) {
    const { form_response: formResponse } = data;
    return {
        action,
        integration_name: INTEGRATION_NAME,
        integration_id: INTEGRATION_ID,
        survey_name: formResponse.definition.title,
        survey_id: formResponse.form_id,
        token: formResponse.token,
        landed_at: getTimestamp(formResponse.landed_at)
    };
}

/**
 * Construct an event.
 * @param {object} properties - Event properties
 * @param {object} customerIds - Customer IDs
 * @param {number} timestamp - Event timestamp
 * @returns {object} - The event object
 */
function returnEvent(properties, customerIds, timestamp) {
    return {
        name: "customers/events",
        data: {
            customer_ids: customerIds,
            event_type: "survey",
            timestamp,
            properties
        }
    };
}

/**
 * Convert a string date to a timestamp.
 * @param {string} stringDate - The string representation of the date
 * @returns {number} - The timestamp
 */
function getTimestamp(stringDate) {
    const date = new Date(stringDate);
    return Math.floor(date.getTime() / 1000);
}

/**
 * Convert a string date to a midday UTC timestamp.
 * @param {string} dateString - The string representation of the date
 * @returns {number} - The midday UTC timestamp
 */
function getMiddayUtcTimestamp(dateString) {
    const date = new Date(dateString);
    date.setUTCHours(12, 0, 0, 0);
    return Math.floor(date.getTime() / 1000);
}

Limitations

Typeform does not force you to add any questions to collect an ID. Bloomreach can only ingest data with at least 1 mappable ID.