Skip to content

Instantly share code, notes, and snippets.

@castroalves
Last active November 26, 2025 00:09
Show Gist options
  • Select an option

  • Save castroalves/e9ca059939d49fecb6e84e89c71677cd to your computer and use it in GitHub Desktop.

Select an option

Save castroalves/e9ca059939d49fecb6e84e89c71677cd to your computer and use it in GitHub Desktop.
Tutorial: Capturing Elementor Leads in Intercom with Next.js

Tutorial: Capturing Elementor Leads in Intercom with Next.js

This guide explains how to connect a WordPress Elementor Pro form to Intercom using a Next.js API route as the middleman.

Prerequisites

  1. WordPress Website with Elementor Pro installed.
  2. Plugin: Telephone field for Elementor Forms (Free) - Required for valid phone formats.
  3. Next.js Application hosting the API route.
  4. Intercom Account with access to Developer settings.

Step 1: Configure the Next.js API Route

Ensure your app/api/leads/route.ts file is set up with the following code. This code is specifically designed to handle the Advanced Data structure sent by Elementor and the strict requirements of Intercom.

import { NextResponse } from "next/server";
import { Client } from "intercom-client";

const intercom = new Client({
  tokenAuth: {
    token: process.env.INTERCOM_ACCESS_TOKEN as string,
  },
});

export async function POST(request: Request) {
  try {
    const contentType = request.headers.get("content-type") || "";
    let data: Record<string, any> = {};

    // 1. Robust Data Parsing
    if (contentType.includes("application/json")) {
      try {
        data = await request.json();
      } catch (e) {
        console.error("JSON parsing failed", e);
        return NextResponse.json(
          { error: "Invalid JSON body" },
          { status: 400 }
        );
      }
    } else {
      const formData = await request.formData();
      formData.forEach((value, key) => {
        data[key] = value.toString();
      });
    }

    // 2. Initialize Variables
    // Elementor Advanced Webhooks send data as keys like 'fields[email][value]'
    const email = data["fields[email][value]"];
    const name = data["fields[name][value]"];
    const phone = data["fields[phone][value]"];
    const jobTitle = data["fields[jobtitle][value]"];

    // 3. Validation
    if (!email) {
      return NextResponse.json(
        { error: "Email is required." },
        { status: 400 }
      );
    }

    // 4. Send to Intercom
    // Only sending the requested fields
    const contact = await intercom.contacts.createLead({
      email: email,
      name: name,
      // Make sure you're using Telephone field for Elementor Forms plugin
      phone: phone,
      customAttributes: {
        // See Step 3 to add these custom attributes
        work_role: jobTitle, // Explicitly mapping jobtitle to custom attributes
        source: "Add a name or URL referrer",
      },
      signedUpAt: Math.floor(Date.now() / 1000),
    });

    return NextResponse.json({
      success: true,
      message: "Lead captured successfully",
      intercom_id: contact.id,
    });
  } catch (error: any) {
    console.error("Intercom Integration Error:", error);
    return NextResponse.json(
      { error: "Failed to process submission", details: error.message },
      { status: 500 }
    );
  }
}

Environment Variables: Create or update your .env.local file with your Intercom Access Token:

INTERCOM_ACCESS_TOKEN=your_token_here

To get this token:

  1. Go to Intercom Developer Hub.
  2. Create a new App (or select an existing one).
  3. Navigate to Configure > Authentication.
  4. Copy the Access Token.

Middleware Configuration (Critical)

If your Next.js project uses middleware.ts (common for authentication like Clerk, NextAuth, or Supabase), you must exclude the API route from protection. If you don't, Elementor's request will be blocked (401 Unauthorized) or redirected (307), causing the webhook to fail.

Example (Generic Middleware matcher): Ensure your matcher excludes /api/leads:

export const config = {
  matcher: [
    /* ... existing matcher ... */
    '/((?!api/leads|_next/static|_next/image|favicon.ico).*)',
  ],
}

Example (Clerk Auth): If using Clerk, add it to publicRoutes or ignoredRoutes:

export default authMiddleware({
  publicRoutes: ["/api/leads"],
});

Step 2: Configure the Elementor Form

Go to your WordPress Admin dashboard and edit the page containing your form with Elementor.

1. Install & Configure Phone Validation (Crucial)

Intercom is very strict about phone numbers. They must include the + prefix and country code (e.g., +5511999999999). The default Elementor "Tel" field does not enforce this, often causing the integration to fail with generic errors.

The Fix:

  1. Install and activate the free plugin: Telephone field for Elementor Forms.
  2. Edit your Elementor Form.
  3. Delete your existing standard "Tel" field.
  4. Add the new "Telephone" field (added by the plugin) to your form.
  5. This field adds a country picker and ensures the submitted value is always formatted correctly (e.g., +1 555... or +55 11...).

2. Set Field IDs

The API route expects specific Field IDs to map the data correctly. Click on each form field and set the ID (under the Advanced tab) to match exactly:

  • Name Field: Set ID to name
  • Email Field: Set ID to email
  • Telephone Field (New): Set ID to phone
  • Job/Role Field: Set ID to jobtitle

3. Configure Actions After Submit

  1. Click on the Form widget.
  2. Go to Content > Actions After Submit.
  3. Add Webhook to the list of actions.

4. Configure Webhook Settings

A new "Webhook" tab will appear in the Elementor sidebar.

  1. Webhook URL: Enter the full URL to your Next.js API route.
  • Dev: https://your-tunnel-url.ngrok.io/api/leads
  • Prod: https://your-domain.com/api/leads
  1. Advanced Data: Toggle this to YES.
  • Crucial: The API code relies on the structure provided by "Advanced Data" (e.g., fields[email][value]). If this is off, the integration will fail.

Step 3: Intercom Attribute Setup

The code sends work_role and source as Custom Attributes. You must define these in Intercom for them to appear cleanly in the UI (though Intercom often creates them automatically on the first sync).

  1. Go to Intercom Settings > Data > People Data.
  2. Create a new attribute called work_role (Text) and `source (Text) if they don't exist.

Step 4: Testing

  1. Open your WordPress page (ensure it's not the editor preview, use the live page or preview link).
  2. Fill out the form with test data. Use the country picker to select your country and type a number.
  3. Submit.
  4. Check Intercom: Go to "Contacts" and look for the new lead. You should see the Name, Email, properly formatted Phone, and the Custom Attributes (Job Title/Role) populated.

Troubleshooting

  • Error 500 / "Failed to process": Check the Next.js console logs.
  • "Email is required": This usually means the Elementor "Advanced Data" switch is OFF, or the Field ID for email is not set to email in Elementor.
  • Intercom API Error (Phone): If you still see errors regarding phone numbers, ensure the "Telephone" plugin is active and the user is actually using the country picker. The plugin should force the + prefix automatically.
  • Webhook Failures (401/307): Verify your Middleware settings (Step 1). The webhook route MUST be public.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment