Skip to content

ENRICHLOOPSINTEGRATIONS CUSTOMER.IO

Firmographics in Customer.io.
No code required.

When someone signs up with a work email, EnrichLoops fills in company industry, size, and headquarters. You wire it with two Customer.io campaigns: one that calls a Loop, and one that receives the result and updates the profile.

  1. 01
    Someone signs up

    Campaign 1 starts

  2. 02
    Call the Loop

    Send domain + email

  3. 03
    EnrichLoops runs

    Company data ready

  4. 04
    Webhook arrives

    Campaign 2 starts

  5. 05
    Profile updates

    Attributes mapped

Why you need
two campaigns.

A Loop accepts a domain and finishes later. Customer.io can send that request from a campaign, but the HTTP response is only a queued task. The company profile shows up afterward, on the Loop’s outbound webhook.

Campaign 1 handles the outbound call. Campaign 2 is a webhook-triggered campaign: you paste its URL into EnrichLoops, and Customer.io updates the person when enrichment completes.

What changes
on the profile.

Before enrichment you mostly have an email. After campaign 2 runs, you can segment and personalize on company fields.

Right after signup
email
alex@rand.org
created_at
just now
company_*
After the EnrichLoops webhook
company_name
RAND
company_industry
Non-profit Organizations
company_employee_count
2822
company_hq_city
Santa Monica
company_hq_country
US
company_type
Nonprofit

Campaign 1.
On signup, call EnrichLoops.

  1. Create a Loop in EnrichLoops. You’ll point its webhook at campaign 2’s URL once that campaign exists.
  2. Create a Customer.io campaign that starts when someone signs up (person created, or your signup event).
  3. Exclude freemail. Filter out gmail.com, yahoo.com, outlook.com, and similar domains so you don’t spend credits on personal addresses.
  4. Add Send and receive data. Use POST to your Loop run URL. Keep Content-Type: application/json. Add Authorization: Bearer YOUR_API_KEY.
  5. Send domain and email in the JSON body. The domain is what EnrichLoops enriches. The email (or id) is how campaign 2 finds the right profile. Customer.io’s webhook campaigns expect an identifier in the payload.
  6. Set the action to send automatically, then send a test with a sample profile.
Request body (Liquid)
{
  "domain": "{{ customer.email | split: '@' | last }}",
  "email": "{{ customer.email }}"
}

Personalize with Liquid. If a value might break JSON, Customer.io recommends filters like strip and escape.

Campaign 2.
Receive and update.

  1. Create a webhook-triggered campaign in Customer.io and copy the webhook URL it generates.
  2. Paste that URL into your EnrichLoops Loop as the webhook destination. It must be HTTPS and publicly reachable.
  3. Run a test enrichment so Customer.io records a sample payload (shape on the right). You’ll use that sample while mapping fields.
  4. Add Create or update profile. Set the identifier to the email (or id) you sent in campaign 1, for example {{ trigger.task.input.email }} when that value is present on task.input.
  5. Map company attributes from trigger.data.* with Liquid or JavaScript, then start the campaign.
Webhook body from EnrichLoops
{
  "task": {
    "id": "de817e0e-8ea2-4a21-b637-d258ae312ae1",
    "object_type": "company",
    "operation": "enrich",
    "status": "succeeded",
    "input": {
      "domain": "rand.org"
    },
    "target": "rand.org",
    "credits_charged": 1,
    "loop_id": "35ba5b47-5b49-40b0-bed9-24edcd66b4a8",
    "idempotency_key": null,
    "created_at": "2026-08-11T23:28:35.803143+00:00",
    "queued_at": "2026-08-11T23:28:35.803143+00:00",
    "started_at": "2026-08-11T23:28:35.734+00:00",
    "finished_at": "2026-08-11T23:28:35.734+00:00",
    "expires_at": "2026-08-11T23:38:35.734+00:00"
  },
  "data": {
    "name": "RAND",
    "about": "RAND is a nonprofit, nonpartisan research organization that provides leaders with the information they need to make evidence-based decisions. The challenges facing humanity are complex. So is the policy landscape decisionmakers must navigate to create positive change. RAND's mission is straightforward. We help improve policy and decisionmaking through research and analysis. Our rigorous research is free from political or commercial pressures so that policy leaders can use the best possible data to make the best possible decisions. Why is this work so vital? Because when RAND can help improve policymaking, we can help make the world a better place for us all. http://www.rand.org/jobs.html",
    "domain": "rand.org",
    "slogan": "We arm leaders with the information they need to tackle the toughest policy problems. Nonprofit, nonpartisan.",
    "created_at": "2026-08-05T01:48:32.729302+00:00",
    "updated_at": "2026-08-11T04:11:02.193296+00:00",
    "linkedin_id": "165654",
    "headquarters": {
      "city": "Santa Monica",
      "country": "United States",
      "postalCode": "90401",
      "countryCode": "US",
      "raw_address": "1776 Main Street, Santa Monica, CA 90401, US",
      "stateProvince": "CA",
      "isHeadquarters": true
    },
    "linkedin_url": "https://linkedin.com/company/rand-corporation",
    "year_founded": 1946,
    "employee_count": 2822,
    "employee_range": "1,001-5,000 employees",
    "last_enriched_at": "2026-08-05T01:48:32.641+00:00",
    "primary_industry": "Non-profit Organizations",
    "enrichment_status": "enriched",
    "organization_type": "Nonprofit",
    "linkedin_followers": 208953
  }
}

Attribute map.

Use these as starting points in Create or update profile. Leave data.about off the profile unless you display long company blurbs somewhere. It’s a poor fit for segments.

EnrichLoopsCustomer.io attributeLiquidWhy it helps
data.namecompany_name{{ trigger.data.name }}Show the company name in messages
data.domaincompany_domain{{ trigger.data.domain }}Join key / skip re-enrichment
data.primary_industrycompany_industry{{ trigger.data.primary_industry }}Industry-specific campaigns
data.organization_typecompany_type{{ trigger.data.organization_type }}Filter nonprofit vs commercial
data.employee_countcompany_employee_count{{ trigger.data.employee_count }}Numeric size scoring
data.employee_rangecompany_employee_range{{ trigger.data.employee_range }}Human-readable size buckets
data.headquarters.citycompany_hq_city{{ trigger.data.headquarters.city }}Local / regional copy
data.headquarters.stateProvincecompany_hq_region{{ trigger.data.headquarters.stateProvince }}State or province targeting
data.headquarters.countryCodecompany_hq_country{{ trigger.data.headquarters.countryCode }}Country routing
data.linkedin_urlcompany_linkedin_url{{ trigger.data.linkedin_url }}Sales or CS follow-up
data.year_foundedcompany_year_founded{{ trigger.data.year_founded }}Company age signals
task.idenrichloops_task_id{{ trigger.task.id }}Deduplicate retries / debug

Before you
go live.

Five checks that catch most of the support tickets we see on this integration.

  • Don’t read company fields from campaign 1’s response

    That response is a queued task. Firmographic data only arrives on the webhook that starts campaign 2.

  • Always send an identifier with the domain

    Webhook-triggered campaigns start from data, not from a person already in the journey. Customer.io expects an email or id in the payload so Create or update profile can target the right person. Put that next to domain in campaign 1.

  • Filter freemail early

    Keep consumer inboxes out of campaign 1. Enrichment on those domains is usually a wasted credit.

  • Enrich once, not on every event

    Trigger on signup, or when company_domain is empty. Page views and track calls are the wrong place to call the Loop.

  • Stick to Customer.io’s webhook setup

    Valid JSON, Liquid cleanup filters, editor test sends, and automatic send on the webhook action. If the UI labels have moved, start from their webhook action and webhook-triggered campaign docs.

More integrations.

HubSpotPipedriveClose
See every guide

Make a little data
go a long way.

Get your API key and put enrichment to work. Start with 100 free credits a month. No card. No sales call.

Get your free API key