# How to Integrate Bolt.new with Intercom

- Tool: Bolt.new
- Difficulty: Intermediate
- Time required: 20 minutes
- Last updated: April 2026

## TL;DR

To integrate Intercom with Bolt.new, add the Intercom JavaScript snippet to your root layout using your app ID — the Messenger widget loads immediately in the WebContainer preview. For REST API features (managing contacts, conversations, articles), create a Next.js API route that uses your Intercom API access token stored in server-side environment variables. Webhooks for real-time conversation events require a deployed URL on Netlify or Bolt Cloud.

## Integrating Intercom's Customer Engagement Platform with Bolt.new

Intercom is more than a live chat widget — it combines real-time Messenger, AI-powered Resolution Bot, targeted in-app messages, product tours, and a help center into a single platform. For Bolt.new developers building SaaS products, Intercom is particularly valuable because its JavaScript API allows you to identify users, track custom events, and trigger targeted messages programmatically, turning it into a lightweight CRM layer on top of your existing app.

The integration in Bolt.new follows the same two-layer pattern as most JavaScript-based tools. The Messenger widget embeds via a small JavaScript snippet in your root layout, loads asynchronously from Intercom's CDN, and works in Bolt's WebContainer preview from the first moment you configure it. The widget requires only your Intercom app ID (a public identifier) to initialize, making it one of the simplest integrations to get running. Once loaded, you can call the Intercom JavaScript API to pass user data — name, email, account creation date, custom attributes — so Intercom users see a complete customer profile before responding.

For operations beyond the widget — reading conversation history, managing contacts, creating help center articles, or triggering automated messages — you use Intercom's REST API through a server-side Next.js API route. These calls use your Intercom API access token, which must stay server-side. Webhooks for real-time events (conversation started, message received, user created) require Intercom to POST to your server, which means they only work after deploying to Netlify or Bolt Cloud. Plan your architecture around this: use the widget for synchronous interactions and webhooks for event-driven automations that don't block the user experience.

## Before you start

- An Intercom account (14-day free trial, paid plans start at $74/month for the Starter plan)
- Your Intercom app ID (found in Settings → Installation → Your app ID — a short alphanumeric string)
- An Intercom API access token (Settings → Developers → API Keys → Your app → Access Token)
- A Bolt.new project using Next.js for server-side API routes
- For webhooks and OAuth: a deployed URL from Netlify or Bolt Cloud (webhooks cannot reach the WebContainer preview)

## Step-by-step guide

### 1. Get Your Intercom App ID and API Access Token

Intercom requires two separate credentials: a public app ID for the Messenger widget and a private access token for the REST API. To find your app ID, log into Intercom and go to Settings → Installation. At the top of the page, you'll see your app ID displayed as a short string like 'abc123xy'. This is public and safe to include in client-side code — it only identifies which Intercom workspace the widget connects to. For the REST API, go to Settings → Developers → API Keys. If you have developer hub access, click on your app (or create one). Under 'Authentication', you'll find your Access Token. If you're on a newer Intercom plan, you may need to create a developer app first: go to developers.intercom.com, sign in, click 'New app', give it a name, and select your workspace. Your access token appears in the Authentication section. This token has full API access — treat it like a password. Store it only as a server-side environment variable without the NEXT_PUBLIC_ prefix.

**Expected result:** You have your Intercom app ID (short alphanumeric string) and your API access token (a long alphanumeric string) saved for configuration.

### 2. Embed the Intercom Messenger Widget

The Intercom Messenger is embedded by calling the window.Intercom() function with your app ID and optional user data. In a Next.js app, you add a client-side component to your root layout that initializes Intercom after the page loads. The initialization call accepts a configuration object where you can set the app_id (required), and optionally provide user identity information: name, email, user_id, and created_at (Unix timestamp). When user data is provided, Intercom shows the agent a complete customer profile. For anonymous visitors, omit user data and Intercom shows the Messenger in 'visitor' mode. The widget loads from Intercom's CDN and appears as a colored circle in the bottom-right corner. It includes the entire Messenger experience — live chat, help center articles, and automated bots — in a single initialization. This works fully in Bolt's WebContainer preview, so you can test the complete chat flow during development. To hide the widget on certain pages (like login or checkout), call window.Intercom('update', { hide_default_launcher: true }) in a useEffect for that page.

```
'use client';
import { useEffect } from 'react';

interface IntercomProviderProps {
  children: React.ReactNode;
  user?: {
    id: string;
    email: string;
    name: string;
    createdAt: number; // Unix timestamp
  };
}

declare global {
  interface Window {
    Intercom?: (command: string, data?: Record<string, unknown>) => void;
    intercomSettings?: Record<string, unknown>;
  }
}

export function IntercomProvider({ children, user }: IntercomProviderProps) {
  const appId = process.env.NEXT_PUBLIC_INTERCOM_APP_ID!;

  useEffect(() => {
    // Load Intercom script
    (function () {
      const w = window;
      const ic = w.Intercom;
      if (typeof ic === 'function') {
        ic('reattach_activator');
        ic('update', w.intercomSettings);
      } else {
        const d = document;
        const i = function (...args: unknown[]) {
          (i as unknown as { q: unknown[] }).q.push(args);
        };
        (i as unknown as { q: unknown[]; c: (...args: unknown[]) => void }).q = [];
        (i as unknown as { c: (...args: unknown[]) => void }).c = function (...args: unknown[]) {
          (i as unknown as { q: unknown[] }).q.push(args);
        };
        w.Intercom = i as unknown as (command: string, data?: Record<string, unknown>) => void;
        const l = function () {
          const s = d.createElement('script');
          s.type = 'text/javascript';
          s.async = true;
          s.src = `https://widget.intercom.io/widget/${appId}`;
          const x = d.getElementsByTagName('script')[0];
          x?.parentNode?.insertBefore(s, x);
        };
        if (document.readyState === 'complete') {
          l();
        } else {
          window.addEventListener('load', l);
        }
      }
    })();

    // Initialize with user data or anonymous
    const config: Record<string, unknown> = { app_id: appId };
    if (user) {
      config.user_id = user.id;
      config.email = user.email;
      config.name = user.name;
      config.created_at = user.createdAt;
    }
    window.Intercom?.('boot', config);

    return () => {
      window.Intercom?.('shutdown');
    };
  }, [appId, user?.id]);

  return <>{children}</>;
}
```

**Expected result:** The Intercom Messenger bubble appears in the bottom-right corner of your Bolt preview. Opening it shows the Messenger with help center articles and a live chat option. Authenticated users appear in Intercom with their name and email.

### 3. Create API Routes for Intercom REST API

Intercom's REST API provides access to contacts, conversations, articles, and more. All calls require a Bearer token authorization header using your access token. Create API routes in Next.js that proxy requests to Intercom's API, keeping the token server-side. The Intercom API is versioned — always include the Intercom-Version header to pin to a specific API version and prevent breaking changes when Intercom releases updates. Key endpoints you'll likely need: GET /contacts to search and filter your contact list, GET /conversations to fetch conversation history, GET /articles to retrieve help center articles. The Intercom API uses cursor-based pagination with a starting_after parameter for large result sets. For most Bolt apps, the most valuable REST API operations are fetching conversation history for a specific user (filtering by email), creating or updating contact records with custom attributes, and reading help center articles for a search feature.

```
// app/api/intercom/contacts/route.ts
import { NextResponse } from 'next/server';

const INTERCOM_API_BASE = 'https://api.intercom.io';
const INTERCOM_VERSION = '2.10';

function getHeaders() {
  return {
    Authorization: `Bearer ${process.env.INTERCOM_ACCESS_TOKEN}`,
    'Intercom-Version': INTERCOM_VERSION,
    'Content-Type': 'application/json',
    Accept: 'application/json',
  };
}

export async function GET(request: Request) {
  const { searchParams } = new URL(request.url);
  const email = searchParams.get('email');

  try {
    let url = `${INTERCOM_API_BASE}/contacts`;
    if (email) {
      // Search by email using filter
      url = `${INTERCOM_API_BASE}/contacts/search`;
      const body = JSON.stringify({
        query: {
          operator: 'AND',
          value: [{ field: 'email', operator: '=', value: email }],
        },
      });
      const response = await fetch(url, {
        method: 'POST',
        headers: getHeaders(),
        body,
      });
      const data = await response.json();
      return NextResponse.json(data);
    }

    const response = await fetch(url, { headers: getHeaders() });
    const data = await response.json();
    return NextResponse.json(data);
  } catch (error: unknown) {
    const e = error as { message: string };
    return NextResponse.json({ error: e.message }, { status: 500 });
  }
}
```

**Expected result:** GET to /api/intercom/contacts?email=user@example.com returns matching Intercom contact records. The access token stays server-side and never appears in the browser.

### 4. Deploy and Configure Intercom Webhooks

The Messenger widget and REST API polling work in Bolt's WebContainer preview. For real-time event processing — reacting when a user starts a conversation, sends a message, or is created — you need Intercom webhooks. Intercom sends POST requests to your webhook URL when these events fire. Since Bolt's WebContainer has no publicly accessible URL, webhook payloads cannot be delivered during development. Deploy to Netlify or Bolt Cloud first. After deploying, go to the Intercom Developer Hub (developers.intercom.com), select your app, go to Webhooks, and add your webhook URL (e.g., https://your-app.netlify.app/api/intercom/webhook). Select the topics you want to subscribe to — 'conversation.created', 'conversation.user.replied', and 'contact.created' are the most commonly used. Intercom signs webhook payloads with a secret from your app settings. Validate this signature in your webhook handler to confirm events come from Intercom and not from spoofed requests. Intercom retries failed webhooks up to 10 times over 8 hours, so your handler should respond quickly with 200 and process the event asynchronously.

```
// app/api/intercom/webhook/route.ts
import { NextResponse } from 'next/server';
import crypto from 'crypto';

export async function POST(request: Request) {
  const rawBody = await request.text();
  const signature = request.headers.get('X-Hub-Signature');

  // Verify webhook signature
  if (process.env.INTERCOM_WEBHOOK_SECRET && signature) {
    const expectedSig = crypto
      .createHmac('sha1', process.env.INTERCOM_WEBHOOK_SECRET)
      .update(rawBody)
      .digest('hex');
    if (`sha1=${expectedSig}` !== signature) {
      return NextResponse.json({ error: 'Invalid signature' }, { status: 403 });
    }
  }

  try {
    const payload = JSON.parse(rawBody);
    const { topic, data } = payload;

    switch (topic) {
      case 'conversation.created':
        console.log('New conversation:', data.item.id);
        break;
      case 'conversation.user.replied':
        console.log('User replied to conversation:', data.item.id);
        break;
      case 'contact.created':
        console.log('New contact created:', data.item.email);
        break;
      default:
        console.log('Unhandled Intercom event:', topic);
    }

    return NextResponse.json({ received: true });
  } catch (error: unknown) {
    const e = error as { message: string };
    return NextResponse.json({ error: e.message }, { status: 500 });
  }
}
```

**Expected result:** After deploying and configuring webhooks in the Intercom Developer Hub, conversation events trigger your webhook handler. The Intercom developer console shows successful 200 responses for each delivery.

## Best practices

- Store INTERCOM_ACCESS_TOKEN as a server-side environment variable (no NEXT_PUBLIC_ prefix) — it provides full access to your contact database and conversation history
- Initialize Intercom with user identity data (name, email, user_id) for authenticated users so agents always have context before responding
- Call Intercom('shutdown') when users log out to prevent the next user on the same device from seeing the previous user's conversation history
- Use the hide_default_launcher option on authentication pages (login, signup) and checkout flows to avoid distracting the user at critical conversion moments
- Proxy all Intercom REST API calls through Next.js API routes and never call Intercom's API directly from client components
- Pin the Intercom API version with the Intercom-Version header to avoid unexpected breaking changes from automatic version upgrades
- Respond to Intercom webhooks within 30 seconds with a 200 status — use async processing for heavy operations to avoid timeouts and retry storms
- Test the Messenger widget in Bolt's WebContainer preview, but deploy before testing webhooks, OAuth flows, or any inbound HTTP event handling

## Use cases

### Personalized Onboarding Messenger with User Identification

Add Intercom Messenger to your SaaS app and identify authenticated users so support agents see their name, email, account age, and plan tier before the conversation starts. Trigger a welcome message when new users log in for the first time to guide them through key features.

Prompt example:

```
Add Intercom Messenger to my Next.js app. In the root layout, load the Intercom JavaScript snippet with my app ID from process.env.NEXT_PUBLIC_INTERCOM_APP_ID. Create a client component IntercomProvider that initializes Intercom with the current user's name, email, userId, and created_at date when they're logged in, and calls Intercom('shutdown') on logout. Show a custom welcome message for users whose account is less than 7 days old: 'Welcome! Need help getting started? I'm here to help.'
```

### Help Center Article Search Widget

Build a search feature that queries your Intercom Help Center articles through the REST API and displays results inline in your app, allowing users to find answers without opening the full Messenger. When an article doesn't answer the question, provide a button to open Messenger with the search query pre-filled.

Prompt example:

```
Create a help search component that calls /api/intercom/articles?query=search_term to search my Intercom Help Center articles. The API route should call Intercom's Articles REST API with INTERCOM_ACCESS_TOKEN. Display up to 5 matching articles as cards with title, summary, and a 'Read more' link that opens in a new tab. Add a 'Still need help? Chat with us' button at the bottom that opens Intercom Messenger with window.Intercom('showNewMessage', 'I searched for: ' + query) pre-populated.
```

### Customer Conversation Dashboard

Build an internal dashboard that shows your team all open Intercom conversations, their status, assigned agent, and time since last reply. The dashboard pulls data from the Intercom Conversations API through a server-side API route, giving your support team a quick overview without logging into Intercom's admin interface.

Prompt example:

```
Create an admin page at /admin/conversations that fetches all open Intercom conversations via /api/intercom/conversations. The API route should call Intercom's Conversations API using INTERCOM_ACCESS_TOKEN, filtering for open conversations only. Display results as a table with columns: customer name, subject/first message, assigned agent, status, and time since last reply. Color-code rows where the last reply was over 4 hours ago in red. Add a 'View in Intercom' link for each conversation.
```

## Troubleshooting

### Intercom Messenger widget doesn't appear in the app

Cause: The most common causes are an incorrect app ID, a content security policy blocking Intercom's CDN, or the boot() call firing before the Intercom script fully loads.

Solution: Open browser DevTools → Console and look for Intercom errors. Type window.Intercom to check if the function exists — if it returns undefined, the script didn't load. Verify NEXT_PUBLIC_INTERCOM_APP_ID is set correctly (no quotes, exact value from Intercom). Check the Network tab for failed requests to widget.intercom.io. If the script loads but the widget doesn't appear, make sure Intercom('boot', { app_id: 'YOUR_ID' }) is being called after the script loads.

```
// Debug in browser console:
console.log('App ID:', process.env.NEXT_PUBLIC_INTERCOM_APP_ID);
console.log('Intercom function:', typeof window.Intercom);
window.Intercom?.('boot', { app_id: 'YOUR_ACTUAL_ID' });
```

### Intercom REST API returns 401 Unauthorized

Cause: The API access token is missing, expired, or incorrectly formatted in the Authorization header. Intercom tokens use Bearer authentication, not Basic auth.

Solution: Verify INTERCOM_ACCESS_TOKEN is set in your .env file. The Authorization header must be 'Bearer YOUR_TOKEN' — the 'Bearer ' prefix is required. Check that the token hasn't been revoked in Settings → Developers → API Keys. Confirm you're using the correct token for the workspace (Intercom tokens are workspace-specific).

```
// Correct header format:
headers: {
  Authorization: `Bearer ${process.env.INTERCOM_ACCESS_TOKEN}`,  // Note: Bearer, not Basic
  'Intercom-Version': '2.10',
}
```

### Intercom webhook signature verification fails (403 response)

Cause: The webhook secret is wrong, or you're parsing the body with request.json() before signature verification — this changes the raw bytes used for the HMAC calculation.

Solution: Always read the raw body with request.text() before computing the HMAC signature, then parse the JSON separately. The HMAC must be computed on the raw request body bytes, not a re-serialized JSON object. Verify INTERCOM_WEBHOOK_SECRET matches exactly what's shown in your Intercom app's webhook settings.

```
// Correct order: read raw text FIRST, then parse
const rawBody = await request.text();
const signature = request.headers.get('X-Hub-Signature');
// Verify signature using rawBody
const payload = JSON.parse(rawBody); // Parse AFTER verification
```

### Webhooks work in testing but never fire in production

Cause: This is the WebContainer limitation. Bolt's WebContainer has no public URL for Intercom to call during development. Testing 'works' in the Intercom developer console's test webhook feature but actual events never arrive.

Solution: Deploy to Netlify or Bolt Cloud first. Then update your Intercom webhook URL to your deployed domain (e.g., https://your-app.netlify.app/api/intercom/webhook). Webhooks require a publicly accessible HTTPS endpoint — the WebContainer cannot provide this.

## Frequently asked questions

### Does Intercom Messenger work in Bolt's WebContainer preview?

Yes. The Intercom Messenger widget is a JavaScript snippet that loads from Intercom's CDN — it works in Bolt's WebContainer preview exactly as it would on any website. You can test the full chat experience, send messages, and see them in your Intercom inbox during development. The limitation is webhooks: incoming events from Intercom require a deployed URL and won't be delivered to the WebContainer.

### How do I find my Intercom app ID?

Log into Intercom, go to Settings → Installation, and look for the JavaScript snippet. Your app ID appears in the snippet as 'app_id: YOUR_APP_ID' — it's a short alphanumeric string like 'abc123xy'. You can also find it in the URL when you're in your Intercom workspace: app.intercom.com/a/apps/YOUR_APP_ID. The app ID is public and safe to include in client-side code.

### What's the difference between Intercom's app ID and API access token?

The app ID is a public identifier used by the Messenger JavaScript snippet to connect the widget to your Intercom workspace — it's safe to expose in client code. The API access token is a private credential used for REST API calls (reading contacts, conversations, articles) — it must be kept server-side in environment variables. Never use your API access token in client-side JavaScript.

### Can I identify users in Intercom without writing custom code?

Yes, for basic identification. Pass name, email, and user_id directly to the Intercom('boot') call when the user logs in. For verified identity (preventing users from spoofing other users' identities), Intercom provides Identity Verification — generate an HMAC hash of the user's ID server-side using your Identity Verification secret and pass it as the user_hash parameter in the boot call.

### How much does Intercom cost for a new Bolt.new app?

Intercom's Starter plan costs $74/month and includes the Messenger, help center, basic automation, and up to 3 seats. The Essential plan for growing teams starts at $169/month. Intercom offers a 14-day free trial with full feature access. For early-stage Bolt apps, Intercom's pricing is one of the higher entry points compared to alternatives like LiveChat or Freshdesk.

---

Source: https://www.rapidevelopers.com/bolt-ai-integrations/intercom
© RapidDev — https://www.rapidevelopers.com/bolt-ai-integrations/intercom
