Skip to content

Customer.io

Set up Customer.io → JustAI data ingestion so JustAI can measure performance (send/open/click/conversion) and power downstream workflows. This is one-time setup - all templates will share this configuration.

JustAI ingests Customer.io reporting events via Reporting Webhooks. This provides the core metrics needed for analysis (opens, clicks, sends, conversions), as well as custom metrics that are important to you.

  • Confirm which Customer.io workspace (Production vs other) you’re connecting.
  • Identify your JustAI org slug (usually your company name in all lower case - feel free to ask us).
  • Make sure you have permissions to create API credentials and webhooks in Customer.io.
  1. In Customer.io, open the campaign workflow and set up your control/treatment split:
    • Control: existing message.
    • Treatment: a Webhook Action followed by the JustAI message.
  2. Configure the Webhook Action request:
    • Method: POST
    • URL: https://worker.justwords.ai/api/generate/<org_slug>
    • Headers:
      • X-Api-Key: <JUSTAI_API_KEY>
      • Content-Type: application/json
    • Body: use the payload recommended in JustAI (Template → Integration Settings → Customer.io).
  3. Configure the Response tab:
    • Attribute name: jw_<template_id>
    • Value: {{ response.copy | json }}
    • Source: choose customer attribute or journey trigger data depending on your attribute scope (see Attribute Scope below).
  4. In JustAI, open the template Integration Settings and set:
    • Campaign ID
    • Webhook Action ID (and Control Action ID if you use multiple controls)
    • Attribute Scope (if enabled — see below)
  5. Save changes, then reference the stored data in your Customer.io message using the appropriate Liquid prefix:
    • Customer attributes: {{ customer.jw_<template_id>.vars.<var_name> }}
    • Journey attributes: {{ journey.jw_<template_id>.vars.<var_name> }}

When the JustAI webhook returns a response, Customer.io stores it as an attribute that you reference in your message Liquid. There are two places this data can live:

ScopeLiquid prefixStored onBest for
Customer attributescustomer.jw_*The customer profileSimple setups, data needed across multiple journeys
Journey attributesjourney.jw_*The current journey runMost setups — avoids bloating the customer profile with per-template data

Journey attributes are scoped to a single journey execution and are automatically cleaned up. Customer attributes persist on the profile indefinitely. For most use cases, journey attributes are recommended to keep customer profiles lean.

For more details, see the Customer.io docs on journey attributes and the journey attributes release notes.

Per account (default): In JustAI, go to Org Integration Settings and set the Default Attribute Scope on your Customer.io workspace. All new templates will inherit this default.

Per template (override): In the template’s Integration Settings, the Attribute Scope selector lets you override the account default. This is useful when migrating — existing templates can stay on customer while new ones use journey.

The webhook response configuration in Customer.io differs slightly depending on the scope:

  • Customer attributes: In the Response tab, click “Set up an attribute”, choose the attribute name, and enter jw_<template_id>.
  • Journey attributes: In the Response tab, click “Set up an attribute”, choose journey trigger data as the source, and enter jw_<template_id>.

The default webhook body works for basic setups. For personalization, pass additional user attributes to JustAI using the attrs field in the request body. JustAI can auto-sync these attributes to keep your personalization data up to date.

Add an attrs object to your webhook body:

{
"attrs": {
"<attribute_name>": "{{ customer.<field_name> }}"
}
}

For example, to pass a user’s persona:

{
"attrs": {
"persona": "{{ customer.persona }}"
}
}

Pass multiple attributes in a single request:

{
"attrs": {
"persona": "{{ customer.persona }}",
"plan": "{{ customer.plan_type }}",
"city": "{{ customer.city }}"
}
}

Use Liquid conditionals to provide default values when attributes might be missing:

{% if customer.plan_type %}{{ customer.plan_type }}{% else %}free{% endif %}

Anything referenceable in Customer.io Liquid is available. You can reference nested objects, arrays, and relationships:

  • {{ customer.company.name }} - nested object property.
  • {{ customer.tags | first }} - first item in an array.
  • {{ customer.subscription.status }} - related object property.

For event-triggered campaigns, event data is accessible via {{ event.<field> }}:

{
"attrs": {
"product_category": "{{ event.product_category }}",
"order_value": "{{ event.order_value }}"
}
}

A complete webhook body with required fields and custom attributes:

{
"template_id": "<template_id>",
"user_id": "{{ customer.id }}",
"tracking_id": "{{ message.journey_id }}",
"attrs": {
"persona": "{{ customer.persona }}",
"plan": "{% if customer.plan_type %}{{ customer.plan_type }}{% else %}free{% endif %}",
"company_name": "{{ customer.company.name }}"
}
}

JustAI supports two ways to pass user data: attrs and fields.

ParameterPurposeUse When
attrsAttributes used for ranking and filtering variantsYou want JustAI to select different content based on user segments (e.g., persona, plan type).
fieldsPersonalization fields returned as hydrated stringsYou need to insert user-specific values (e.g., first name) into the generated content without affecting variant selection.

Use fields for simple personalization like names or account details:

{
"fields": {
"first_name": "{{ customer.first_name }}",
"account_number": "{{ customer.account_id }}"
}
}

You can combine both in the same request:

{
"attrs": {
"persona": "{{ customer.persona }}",
"plan": "{{ customer.plan_type }}"
},
"fields": {
"first_name": "{{ customer.first_name }}"
}
}

In this example, JustAI uses persona and plan to select the best variant, then hydrates first_name into the returned content.

For more details, see the Customer.io docs on Webhook Actions and Liquid personalization.

Create an App API key in your Customer.io workspace:

  • Navigate to Workspace settingsAPI and Webhook CredentialsApp APi Keys.
  • Suggested values:
    • Name: JustAI
    • Workspace: Production (or your chosen workspace)

Customer.io API Key Dashboard

In the JustAI console:

  1. Open Org Integration Settings.
  2. Select Customer.io as the ESP integration.
  3. Choose the appropriate workspace (for example, Production).
  4. Paste the Customer.io API key and save changes.

Console Customer.io API Settings

Generate a JustAI API key.

Store the key in a password manager. You’ll typically use this later for Customer.io “Webhook Action” calls.

4) Create a Reporting Webhook in Customer.io

Section titled “4) Create a Reporting Webhook in Customer.io”

In Customer.io, create a new Reporting Webhook:

  1. Go to Data & IntegrationsIntegrationsAdd IntegrationReporting Webhook.
  2. Fill out the form:
    • Webhook Name: JustAI
    • Endpoint: https://worker.justwords.ai/api/webhook/cio/<org_slug>
      • Replace <org_slug> with your org’s name.
    • Events: select the events you want JustAI to ingest (start with send/open/click/conversion).
    • Options: Send only the first time the event occurs.
  3. Press Save and Enable Webhook.

CIO Webhook Settings

Customer.io conversion metrics are tied to a campaign. If you need additional metrics, you can send custom events to JustAI for correlation with message sends within a time window.

Options:

  • Daily batch ingestion via S3 (write data to a shared S3 bucket).
  • Streaming ingestion via a JustAI events webhook API (similar shape to the Customer.io webhook endpoint above).

Please reach out to our team if you need to add custom events and we can help you integrate them.

  • Webhook never fires: confirm the Reporting Webhook is enabled in Customer.io and the endpoint is correct (including <org_slug>).
  • No events arriving: confirm you selected the relevant events and that you are sending emails/triggering events in the correct workspace.
  • Credentials issues: re-check which Customer.io workspace you created the API key in, and that the same workspace is selected in JustAI.