Guides

How Do I Connect Leadpipe to Attio?

Send identified website visitors into Attio as People and Companies, with intent signals attached. Full walkthrough with field mapping and deduping.

Elene Marjanidze Elene Marjanidze · · 10 min read
How Do I Connect Leadpipe to Attio?

Your Attio workspace has clean pipeline data, relational objects, and a team that actually maintains it. What it does not have is an intent layer. Most of the people looking at your pricing page never show up inside a record, so your reps work from form fills and their inbox, not from the buyers already circling your site.

This guide closes that gap in about 20 minutes. I am Elene, and I write most of Leadpipe’s integration recipes. Below is the exact path I give Attio users when they ask how to pipe identified visitors into People and Companies, attach the right intent fields, and dedupe cleanly so your graph stays tidy.


What you will build

A pipeline where every identified US B2B visitor on your site lands in Attio as a Person tied to their Company, with last-page, intent score, pages viewed, and visit duration attached, plus a new list entry if they hit a high-intent page.


Prerequisites

RequirementNotes
Leadpipe accountStart free with 500 leads, no card
Attio workspaceAny paid tier with API access (Pro or above)
Zapier account (optional)Starter or Professional if you want no-code
Attio adminNeeded to create attributes on People and Companies
Time20-30 minutes

If you would rather skip Attio entirely and look at the CRMs we have full-depth recipes for, the Leadpipe + Salesforce integration and Zoho CRM recipe follow the same structure.


How the pieces fit

Visitor on your site


  Leadpipe pixel
  (identifies 30-40%+ of US B2B traffic)


  Webhook (First Match)


  Zapier OR your own middleware

       ├─ Attio: Upsert Company (match on domain)
       └─ Attio: Upsert Person (match on email), link to Company


  Attio list: "Website visitors - last 7 days"

Attio does not have a native Leadpipe connector yet, so the integration runs over webhooks. That is the same path the Pipedrive recipe uses, and it is more flexible than a packaged app.


Step 1: Configure the Leadpipe webhook

In the Leadpipe dashboard, go to Settings, Integrations, Webhooks, and click Add Webhook.

  1. Paste a destination URL (you will generate this in Step 2).
  2. Set the trigger to First Match. This fires once the first time a visitor is identified. Use Every Update only if you want return-visit signals to flow in as record updates.
  3. Choose the fields to send. For Attio I recommend the full payload so you have room to grow.
  4. Save and fire a test event.

Leadpipe sends the same webhook schema we cover in the webhook payload reference. An identified visitor payload looks like this:

{
  "email": "maria.lopez@acme.io",
  "first_name": "Maria",
  "last_name": "Lopez",
  "phone": "+1-415-555-0139",
  "company_name": "Acme.io",
  "company_domain": "acme.io",
  "company_industry": "B2B SaaS",
  "company_employee_count": 180,
  "company_linkedin_url": "linkedin.com/company/acme-io",
  "job_title": "Head of Growth",
  "seniority": "Head",
  "department": "Marketing",
  "linkedin_url": "linkedin.com/in/marialopezgrowth",
  "city": "San Francisco",
  "state": "California",
  "country": "US",
  "page_url": "/pricing",
  "pages_viewed": ["/", "/features", "/pricing"],
  "visit_duration": 241,
  "referrer": "google.com",
  "intent_score": 78,
  "matched_topics": ["sales engagement", "lead routing"],
  "return_visit": false
}

GDPR note. For EU and UK visitors, Leadpipe defaults to company-level identification unless the visitor has given affirmative consent. Your Attio payloads for those regions will usually show company data without person fields, which is correct behavior, not missing data.


Step 2: Create the Attio attributes

Attio gives you flexible custom attributes on any object. Before routing data in, add these to your People and Companies objects.

On Companies

Attribute nameTypePurpose
Last visit pageTextThe page that triggered the hit
Last visit atTimestampWhen the visit happened
Visits last 30 daysNumberRolling counter, incremented by Zapier
Intent topicsMulti-selectCategories Leadpipe matched
Intent scoreNumber1-100, from Leadpipe
Leadpipe sourceSelectValues: First Match, Update, Ad click

On People

Attribute nameTypePurpose
LinkedIn URLURLHandy for fast verification
Last page viewedTextPer-person, not per-company
Visit duration secondsNumberEngagement proxy
DepartmentSelectMarketing, Sales, Product, Engineering, Ops, Finance, Exec, Other
SenioritySelectIC, Manager, Head, Director, VP, C-level, Founder
Return visitorCheckboxFlipped when Leadpipe sends return_visit: true

Keep attribute names consistent. Attio’s API surfaces them with stable slugs, and your Zapier mappings will break if you rename them later.


Step 3: Wire it up with Zapier (no-code path)

Zapier is the fastest path for teams without engineering bandwidth. For a broader view of what you can wire up this way, our Zapier automation recipes post is a useful companion.

  1. Create a new Zap. Trigger: Webhooks by Zapier, Catch Hook. Copy the URL and paste it into the Leadpipe webhook destination from Step 1.
  2. Fire a test event. Zapier will display all the fields.
  3. Add a Filter step. Suggested rule: only continue if email does not contain gmail.com, yahoo.com, outlook.com, icloud.com and visit_duration is greater than 20. This keeps consumer traffic and bounces out of Attio.
  4. Action: Attio, Find or Create Company. Match on company_domain. If no match, create using company_name, company_industry, company_employee_count, company_linkedin_url. Update the Last visit page, Last visit at, Intent score, Intent topics attributes.
  5. Action: Attio, Find or Create Person. Match on email. Create using first_name, last_name, job_title, linkedin_url, city, state, country, phone. Link the Person to the Company created in Step 4.
  6. Action: Attio, Add to List. Pick the list called “Website visitors - last 7 days” (create it in Attio first). This is your running watchlist.

Switch the Zap on. Identified US B2B visitors should appear in Attio within seconds of a page view.


Step 4: Direct API path for higher volume

If your site pushes more than a few thousand identifications per month, skip Zapier. Point Leadpipe’s webhook at a small middleware (Node, Python, or a serverless function) that hits Attio’s REST API directly.

// POST /leadpipe-webhook
// Env: ATTIO_API_KEY
import fetch from 'node-fetch';

export async function handler(req) {
  const v = req.body;
  const domain = v.company_domain?.toLowerCase();
  if (!domain) return { statusCode: 200, body: 'skipped: no domain' };

  // Upsert Company
  const companyRes = await fetch(
    'https://api.attio.com/v2/objects/companies/records?matching_attribute=domains',
    {
      method: 'PUT',
      headers: {
        Authorization: `Bearer ${process.env.ATTIO_API_KEY}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        data: {
          values: {
            domains: [{ domain }],
            name: [{ value: v.company_name }],
            last_visit_page: [{ value: v.page_url }],
            last_visit_at: [{ value: new Date().toISOString() }],
            intent_score: [{ value: v.intent_score }],
            intent_topics: (v.matched_topics || []).map((t) => ({ option: t })),
          },
        },
      }),
    }
  );

  const companyId = (await companyRes.json()).data?.id?.record_id;

  // Upsert Person
  if (v.email) {
    await fetch(
      'https://api.attio.com/v2/objects/people/records?matching_attribute=email_addresses',
      {
        method: 'PUT',
        headers: {
          Authorization: `Bearer ${process.env.ATTIO_API_KEY}`,
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          data: {
            values: {
              email_addresses: [{ email_address: v.email }],
              name: [{ first_name: v.first_name, last_name: v.last_name }],
              job_title: [{ value: v.job_title }],
              linkedin: [{ value: v.linkedin_url }],
              company: [{ target_object: 'companies', target_record_id: companyId }],
              last_page_viewed: [{ value: v.page_url }],
              visit_duration_seconds: [{ value: v.visit_duration }],
              return_visitor: [{ value: v.return_visit }],
            },
          },
        }),
      }
    );
  }

  return { statusCode: 200, body: 'ok' };
}

The matching_attribute query parameter is Attio’s upsert mechanism. Use domains for Companies and email_addresses for People. Your records stay deduped without any extra logic.


What this looks like in practice

Maria, Head of Growth at Acme.io, Googles “sales engagement vs cold email” and lands on your comparison page. Two days later she returns and reads your pricing page for four minutes.

Here is what flows into Attio:

  1. First visit. Leadpipe matches Maria. Webhook fires. Your Zap creates Acme.io as a Company (domain acme.io, 180 employees, B2B SaaS), creates Maria as a Person linked to that Company (Head of Growth, LinkedIn attached), sets Intent score 62, Intent topics “sales engagement”, and adds the Company to your “Website visitors - last 7 days” list.
  2. Return visit. Leadpipe fires another First Match webhook because the pixel sees a new cookie, or an Every Update webhook if you enabled it. Your upsert updates the Company’s Last visit page to /pricing, bumps Intent score to 78, ticks Return visitor on Maria’s Person record, and refreshes Last visit at.
  3. Your AE opens the Attio list at 9 am, sees Acme.io at the top with intent score 78 and a pricing-page visit, and sends a one-line Loom on the specific issue Maria would care about based on her pages viewed.

That loop only works if the data is clean. Which leads to the part people get wrong.


Troubleshooting and edge cases

Duplicate Companies by domain variants. Attio does not normalize www.acme.io vs acme.io for you. Lowercase and strip the www. in your middleware before the upsert. If you are on the Zapier path, add a Formatter step that does trim, lowercase, and replace "www." with "".

Person with no email. Sometimes Leadpipe returns a match with company data and no business email (this is expected on a subset of identifications, and the default for EU and UK visitors). Skip the Person create, still upsert the Company, and set a Company attribute like “Anonymous visits this month +1” so the account still climbs your watchlist.

GDPR defaults for EU visitors. A visitor from Germany will usually come through as company-level only. That is Leadpipe respecting GDPR, not a bug. Keep your Person mapping tolerant of missing fields. Our GDPR compliance notes post goes deeper on why this matters.

Too many low-value records. If Attio starts feeling noisy, tighten the filter. Raise the visit_duration threshold to 45 seconds, or require intent_score over 40. You can always loosen it later.

Mapping the intent topics field. Attio’s Multi-select needs matching option values. Pre-create your top 20 intent topics (sales engagement, CRM, ABM, outbound, SEO, analytics, and so on) inside Attio, then have Zapier drop unknown values so it does not fail the record write.

Linking People to the right Company. Always upsert the Company first and pass its record ID into the Person create, or use Attio’s Company linking by domain. Do not rely on free-text company name matching, it breaks on “Acme.io” vs “Acme, Inc.”


Extending the recipe

Once the basic pipe is live, these additions are worth the hour:

And if you are picking a CRM in the first place, the same webhook payload flows into Salesforce, Pipedrive, and HubSpot via Clay. The Attio recipe is intentionally similar so you can swap CRMs without rebuilding the data flow.


Why this stack pays off

Attio is a good graph of your pipeline, but a graph without live inputs is just a snapshot. When Leadpipe is wired in, your People object gets 30-40%+ of your US B2B visitors in real time, your Companies object starts tracking which of your target accounts are actually in-market, and your lists become a queue reps can work instead of a static report.

A CRM without a visitor-intent layer is a lagging indicator. Wire the intent layer in, and your CRM becomes a leading one.

Every plan ships with the same identity graph, 23 REST endpoints, webhooks, and a 27-tool MCP server. Start in 5 minutes →