Skip to main content
RapidDev - Software Development Agency
v0-integrationsNext.js API Route

How to Integrate Intercom with V0

To integrate Intercom with V0 by Vercel, embed the Intercom Messenger JavaScript snippet in your Next.js layout, create an API route to manage conversations and contacts using the Intercom REST API, and store your app ID and access token in Vercel environment variables. Your app can show the live chat widget, identify users, track events, and pull conversation data into custom dashboards.

What you'll learn

  • How to embed the Intercom Messenger widget in a V0-generated Next.js app and identify logged-in users
  • How to create a Next.js API route that manages Intercom contacts using the REST API
  • How to track custom events in Intercom when users take actions in your V0 app
  • How to build a custom conversation inbox view using the Intercom REST API
  • How to securely store Intercom credentials in Vercel environment variables for both the widget and the API
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate17 min read25 minutesCommunicationApril 2026RapidDev Engineering Team
TL;DR

To integrate Intercom with V0 by Vercel, embed the Intercom Messenger JavaScript snippet in your Next.js layout, create an API route to manage conversations and contacts using the Intercom REST API, and store your app ID and access token in Vercel environment variables. Your app can show the live chat widget, identify users, track events, and pull conversation data into custom dashboards.

Add Intercom Live Chat and Customer Messaging to V0-Generated Next.js Apps

Intercom is the customer messaging platform of choice for most SaaS products — its Messenger widget provides live chat support, product announcements, and automated onboarding sequences through a single code snippet. Adding Intercom to a V0-generated Next.js app takes two forms: the widget integration (adding the chat bubble to all pages) and the API integration (building custom support dashboards, syncing user data, and triggering messaging from your backend).

The widget side of the integration is straightforward: Intercom provides a JavaScript snippet that initializes the Messenger with your App ID. In Next.js App Router, the cleanest way to load it is via a client component wrapper in your root layout that calls window.Intercom() with user identification data when a session is active. This ensures the chat bubble appears on all pages and correctly identifies logged-in users so support agents see the user's name, email, plan, and usage data alongside each conversation.

The API side enables richer scenarios: creating or updating contacts when users sign up, logging custom events (like 'user_upgraded' or 'project_created'), fetching open conversations for a custom support inbox, or sending targeted messages based on user behavior. The Intercom REST API is RESTful with comprehensive documentation covering contacts, conversations, messages, tags, notes, and companies. Your Next.js API routes proxy these calls using an access token that stays on the server, making the pattern secure and straightforward to deploy on Vercel.

Integration method

Next.js API Route

Intercom integrates with V0-generated Next.js apps through two channels: a client-side Messenger widget (the chat bubble) loaded via a script tag in your Next.js layout, and server-side API routes using the Intercom REST API for managing contacts, conversations, and events. The Messenger widget uses your Intercom App ID (a public identifier safe for the browser), while the REST API uses a private access token stored in Vercel environment variables that never reaches the client. V0 generates the UI components that interact with Intercom, and the Next.js App Router handles both the widget injection and server-side API calls.

Prerequisites

  • An Intercom account — create one at intercom.com (14-day free trial, then paid plans starting at $39/month)
  • Your Intercom App ID — found in Intercom Settings → Installation → Web → Your App ID (a short alphanumeric string like 'abc12def')
  • An Intercom access token — go to Intercom Settings → Developers → Developer Hub → Your App → Authentication → Access Token (or create one with the necessary permissions)
  • A V0 account at v0.dev and a Vercel account for deployment
  • An existing authentication system in your app (Clerk, NextAuth, or similar) — Intercom user identification works best when you can provide the logged-in user's ID and email

Step-by-step guide

1

Embed the Intercom Messenger Widget in Next.js Layout

The Intercom Messenger widget is a JavaScript snippet that initializes the chat bubble on your site. In Next.js App Router, the correct place to add it is in your root layout (app/layout.tsx) using a client component — the widget calls browser APIs (window.Intercom) which are not available in Server Components. Create a separate IntercomProvider client component that uses useEffect to load and initialize the Intercom script, then import it into your root layout. The Intercom initialization accepts user identification data: user_id (your internal user ID), email, name, and custom attributes like plan, created_at (Unix timestamp of account creation), and any product-specific data you want visible to support agents. If your app uses an authentication solution like Clerk or NextAuth, read the logged-in user's data in the provider component and pass it to the Intercom boot call. The Intercom App ID is safe to expose in client-side code — it is a public identifier, not a secret. Set it as NEXT_PUBLIC_INTERCOM_APP_ID in your Vercel environment variables so V0-generated components can access it. For apps requiring identity verification (to prevent users from impersonating each other in Intercom), you will also need to generate an HMAC hash of the user ID using your Intercom Identity Verification secret and pass it as user_hash — generate this hash in a server action or API route, never in client code, and pass it down as a prop to the provider component.

V0 Prompt

Create an IntercomProvider client component ('use client') that loads the Intercom Messenger. On mount, call window.Intercom('boot', { app_id: process.env.NEXT_PUBLIC_INTERCOM_APP_ID, user_id: props.userId, email: props.email, name: props.name, created_at: props.createdAt }) if userId is provided, or window.Intercom('boot', { app_id: process.env.NEXT_PUBLIC_INTERCOM_APP_ID }) for anonymous users. On unmount, call window.Intercom('shutdown'). Accept userId, email, name, and createdAt as optional props. Also create a useIntercom hook that exposes showChat(), hideChat(), and trackEvent(name, metadata) methods using window.Intercom. Export both the provider and the hook.

Paste this in V0 chat

components/IntercomProvider.tsx
1// components/IntercomProvider.tsx
2'use client';
3
4import { useEffect } from 'react';
5
6declare global {
7 interface Window {
8 Intercom: (...args: unknown[]) => void;
9 intercomSettings: Record<string, unknown>;
10 }
11}
12
13interface IntercomProviderProps {
14 userId?: string;
15 email?: string;
16 name?: string;
17 createdAt?: number; // Unix timestamp
18 customAttributes?: Record<string, string | number | boolean>;
19 children: React.ReactNode;
20}
21
22export function IntercomProvider({
23 userId,
24 email,
25 name,
26 createdAt,
27 customAttributes,
28 children,
29}: IntercomProviderProps) {
30 const appId = process.env.NEXT_PUBLIC_INTERCOM_APP_ID;
31
32 useEffect(() => {
33 if (!appId) return;
34
35 // Load Intercom script
36 const script = document.createElement('script');
37 script.src = `https://widget.intercom.io/widget/${appId}`;
38 script.async = true;
39 document.head.appendChild(script);
40
41 script.onload = () => {
42 const bootData: Record<string, unknown> = {
43 app_id: appId,
44 ...customAttributes,
45 };
46
47 if (userId) {
48 bootData.user_id = userId;
49 bootData.email = email;
50 bootData.name = name;
51 bootData.created_at = createdAt;
52 }
53
54 window.Intercom('boot', bootData);
55 };
56
57 return () => {
58 // Cleanup on unmount
59 if (window.Intercom) {
60 window.Intercom('shutdown');
61 }
62 document.head.removeChild(script);
63 };
64 }, [appId, userId, email, name, createdAt]);
65
66 return <>{children}</>;
67}
68
69export function useIntercom() {
70 const showChat = () => window.Intercom?.('show');
71 const hideChat = () => window.Intercom?.('hide');
72 const trackEvent = (eventName: string, metadata?: Record<string, unknown>) => {
73 window.Intercom?.('trackEvent', eventName, metadata);
74 };
75 const updateUser = (attributes: Record<string, unknown>) => {
76 window.Intercom?.('update', attributes);
77 };
78
79 return { showChat, hideChat, trackEvent, updateUser };
80}

Pro tip: Update the Intercom session when the user's plan or key attributes change by calling window.Intercom('update', { plan: 'pro' }) — this keeps your support agents' view of each user current without a full page reload.

Expected result: The Intercom chat bubble appears in the bottom-right corner of your app. For logged-in users, the Intercom agent dashboard shows the user's name, email, and any custom attributes you passed in the boot call.

2

Create Intercom Contact and Event API Routes

Create Next.js API routes for server-side Intercom operations that require your private access token. The most common server-side use cases are: creating or updating contacts when users sign up (to sync user data before they start a chat), logging events when users take key actions (to power Intercom's automation and messaging triggers), and fetching conversations for a custom support inbox. The Intercom REST API base URL is https://api.intercom.io and all requests use your access token in the Authorization header as a Bearer token, plus an Intercom-Version header set to '2.11' (or the current version). Contacts are created via POST /contacts with a role of 'user' and the user's email, external_id, and name. Events are logged via POST /events with the event_name, user_id, created_at (Unix timestamp), and an optional metadata object with additional context. Conversations are fetched via GET /conversations with query parameters for filtering. The Intercom API returns standard HTTP error codes: 401 for invalid access token, 403 for insufficient permissions on a specific resource, 404 for missing resources, and 422 for validation errors on POST requests. Error responses include an errors array with type and message fields that describe the issue clearly. The access token should be stored as INTERCOM_ACCESS_TOKEN in Vercel environment variables without any NEXT_PUBLIC_ prefix — it is a server-only secret.

app/api/intercom/events/route.ts
1// app/api/intercom/events/route.ts
2import { NextRequest, NextResponse } from 'next/server';
3
4const INTERCOM_API = 'https://api.intercom.io';
5const INTERCOM_VERSION = '2.11';
6
7async function intercomRequest(path: string, options: RequestInit = {}) {
8 const token = process.env.INTERCOM_ACCESS_TOKEN;
9 if (!token) throw new Error('INTERCOM_ACCESS_TOKEN is not configured');
10
11 const response = await fetch(`${INTERCOM_API}${path}`, {
12 ...options,
13 headers: {
14 Authorization: `Bearer ${token}`,
15 'Content-Type': 'application/json',
16 Accept: 'application/json',
17 'Intercom-Version': INTERCOM_VERSION,
18 ...((options.headers as Record<string, string>) || {}),
19 },
20 });
21
22 const data = await response.json();
23
24 if (!response.ok) {
25 const message = data?.errors?.[0]?.message || `Intercom API error ${response.status}`;
26 throw new Error(message);
27 }
28
29 return data;
30}
31
32export async function POST(request: NextRequest) {
33 let body: {
34 event_name: string;
35 user_id: string;
36 metadata?: Record<string, string | number | boolean>;
37 };
38
39 try {
40 body = await request.json();
41 } catch {
42 return NextResponse.json({ error: 'Invalid request body' }, { status: 400 });
43 }
44
45 const { event_name, user_id, metadata } = body;
46
47 if (!event_name || !user_id) {
48 return NextResponse.json(
49 { error: 'event_name and user_id are required' },
50 { status: 400 }
51 );
52 }
53
54 try {
55 await intercomRequest('/events', {
56 method: 'POST',
57 body: JSON.stringify({
58 event_name,
59 user_id,
60 created_at: Math.floor(Date.now() / 1000),
61 metadata: metadata || {},
62 }),
63 });
64
65 return NextResponse.json({ success: true });
66 } catch (error) {
67 const message = error instanceof Error ? error.message : 'Failed to track event';
68 return NextResponse.json({ error: message }, { status: 500 });
69 }
70}

Pro tip: Intercom events are immutable once logged — you cannot delete or edit them. Use descriptive event names in snake_case like 'project_created', 'subscription_upgraded', or 'onboarding_completed' rather than generic names you might want to repurpose later.

Expected result: POST /api/intercom/events with { event_name: 'project_created', user_id: 'user_123', metadata: { project_name: 'My App' } } logs the event in Intercom and the event appears in the user's profile timeline in the Intercom dashboard.

3

Connect Components to Intercom and Test Locally

Update your V0-generated components to use Intercom for user identification, event tracking, and triggering the chat widget. Wrap your root layout component with the IntercomProvider, passing the logged-in user's data as props. For apps using Clerk authentication, access the user data in a server component and pass it to the client IntercomProvider. For apps using NextAuth v5, use the auth() function in the layout server component to get session data. The useIntercom hook you created makes it easy to trigger Intercom actions from any component — call trackEvent('button_clicked', { button: 'upgrade' }) when users click key buttons, and showChat() when they click support links. Test locally by adding NEXT_PUBLIC_INTERCOM_APP_ID and INTERCOM_ACCESS_TOKEN to your .env.local file, running npm run dev, and navigating to your app. You should see the Intercom bubble appear in the bottom-right corner immediately. Open the Intercom dashboard to verify that the boot call registered with the correct user data — the user should appear in Intercom's contacts with the attributes you passed. For testing event tracking, trigger an action in your app and check the user's event timeline in Intercom to verify events are arriving correctly. If you're using identity verification (recommended for production), generate the user_hash in a Server Action using the crypto module and the HMAC-SHA256 algorithm with your Intercom Identity Verification secret.

V0 Prompt

Update the app to use Intercom properly. Add a 'Get Help' button to the navigation bar that calls window.Intercom('show') using the useIntercom hook. On the settings page, when the user updates their profile and saves successfully, call trackEvent('profile_updated', { fields_changed: 'name,email' }). Add an Intercom identification call when the user logs in, passing their user_id, email, name, and account creation date. Display a banner on the dashboard saying 'Questions? Chat with us!' with a button that opens Intercom chat. Remove any placeholder support email links and replace them with Intercom chat triggers.

Paste this in V0 chat

Pro tip: Use Intercom's 'hide_default_launcher' option in the boot call if you want to remove the default bubble and use your own custom button — set hide_default_launcher: true in the boot data and call window.Intercom('show') from your own button.

Expected result: The Intercom chat bubble appears on all pages, logged-in users are identified with their correct name and email in the Intercom agent view, and events appear in user timelines in the Intercom dashboard when triggered.

4

Add Credentials to Vercel and Deploy

Push your code to GitHub and configure Intercom credentials in Vercel. In the Vercel Dashboard → your project → Settings → Environment Variables, add two variables: NEXT_PUBLIC_INTERCOM_APP_ID with your Intercom App ID (the short public identifier like 'abc12def' — found in Intercom Settings → Installation → Web). This variable needs the NEXT_PUBLIC_ prefix because the Messenger widget is loaded on the client side and needs access to the App ID in browser code. Add INTERCOM_ACCESS_TOKEN with your full access token (a long string — generated in Intercom Settings → Developers → Developer Hub → Your App → Authentication). This variable must NOT have the NEXT_PUBLIC_ prefix because it grants full API access and must stay server-side only. Set both variables for Production, Preview, and Development environments. For NEXT_PUBLIC_INTERCOM_APP_ID, you can safely use the same value in all environments since it is not a secret. For INTERCOM_ACCESS_TOKEN, consider using a different app or token for Preview deployments to avoid test conversations appearing in your production Intercom inbox. After saving, redeploy your project. Test the deployed app by opening it in your browser — the Intercom bubble should appear within a few seconds of page load. Verify in your Intercom dashboard that the deployment URL appears as a source for any test conversations you create. If you need to implement Intercom's identity verification feature for security (preventing users from impersonating others), generate the HMAC-SHA256 hash of the user ID using the INTERCOM_IDENTITY_VERIFICATION_SECRET environment variable in a server action.

Pro tip: Intercom App IDs are workspace-specific — if you have separate Intercom workspaces for development and production, use the development workspace App ID for Preview deployments and the production workspace ID for Production to keep test conversations separate.

Expected result: The Vercel deployment shows the Intercom chat bubble on all pages. New conversations started from the deployed app appear in your Intercom inbox with the correct user identification data and source URL.

Common use cases

Authenticated Live Chat with User Identity

The Intercom Messenger widget appears on all pages of your app and automatically identifies logged-in users so support agents see their name, email, account type, and usage stats alongside every conversation. New users see onboarding messages automatically triggered by Intercom.

V0 Prompt

Create a SaaS application layout with a top navigation bar showing logo, navigation links, user avatar, and account dropdown. Include an Intercom chat widget loader component that initializes Intercom with the logged-in user's name, email, and user ID (passed as props from the layout). The component should call window.Intercom('boot', userData) on mount and window.Intercom('shutdown') on logout. Add a 'Support' button in the nav that calls window.Intercom('show') to open the chat. Display a subtle help icon in the bottom-right corner as a fallback. Use a clean SaaS dashboard aesthetic with dark sidebar navigation.

Copy this prompt to try it in V0

Custom Support Inbox Dashboard

An internal support dashboard that pulls open Intercom conversations into a custom interface, showing conversations with customer names, message previews, assigned agents, and response times — without requiring support agents to use Intercom's own interface.

V0 Prompt

Build a support inbox dashboard with a left panel listing open conversations sorted by most recent, each showing the customer name, conversation preview snippet, time since last message, and a colored badge for response status (Unread/Waiting/Snoozed). The main panel shows the selected conversation with the full message thread, customer profile card (name, email, plan, signup date), quick-reply textarea, and action buttons for Close, Snooze, and Assign. The inbox fetches data from GET /api/intercom/conversations and updates in real time. Use a clean professional support tool design with light gray backgrounds and blue action buttons.

Copy this prompt to try it in V0

User Lifecycle Event Tracker

Track key product events to Intercom when users complete actions in your app — account creation, first project, subscription upgrade. These events power Intercom's segmentation and automated messaging, enabling you to send the right message at the right moment in the user journey.

V0 Prompt

Create an account settings page with sections for profile details, subscription plan (showing current plan with an upgrade button), and notification preferences. When the user clicks 'Upgrade Plan' and completes checkout (calling POST /api/stripe/checkout), also send a POST to /api/intercom/events with event_name 'subscription_upgraded' and plan metadata. Show a success banner after upgrade. The settings page should have a clean tabbed layout with a sidebar navigation and form inputs that save automatically on blur.

Copy this prompt to try it in V0

Troubleshooting

Intercom widget does not appear on the page after deployment

Cause: NEXT_PUBLIC_INTERCOM_APP_ID is not set in Vercel, was set without the NEXT_PUBLIC_ prefix, or was added after the last deployment (NEXT_PUBLIC_ variables are inlined at build time and require a redeployment to take effect).

Solution: In Vercel Dashboard → Settings → Environment Variables, verify NEXT_PUBLIC_INTERCOM_APP_ID exists with the NEXT_PUBLIC_ prefix and is set for the Production environment. After verifying or adding the variable, redeploy from the Deployments tab — changes to NEXT_PUBLIC_ variables only take effect after a full redeployment, not a soft restart.

Intercom shows the user as 'Guest' even though they are logged in

Cause: The IntercomProvider is not receiving the user's data as props, the user data is empty or null when the component mounts, or the Intercom 'boot' call fires before the user session is loaded.

Solution: Ensure the IntercomProvider receives actual user data and not null or undefined values. In Next.js App Router, read the user session in the root layout's server component and pass it as props to the client-side IntercomProvider. Add a conditional check — only pass user identification data to the Intercom boot call if userId is defined and not empty.

typescript
1// Only identify users when data is confirmed available
2if (userId && email) {
3 window.Intercom('boot', { app_id: appId, user_id: userId, email, name });
4} else {
5 window.Intercom('boot', { app_id: appId }); // Anonymous visitor
6}

Intercom API route returns 401 Unauthorized

Cause: The INTERCOM_ACCESS_TOKEN environment variable is not set in Vercel, has been revoked in Intercom, or was accidentally set with the NEXT_PUBLIC_ prefix which strips it from server-side access.

Solution: Navigate to Intercom Settings → Developers → Developer Hub → Your App → Authentication and verify the access token is active. Regenerate it if needed. In Vercel Dashboard → Settings → Environment Variables, confirm INTERCOM_ACCESS_TOKEN exists without any NEXT_PUBLIC_ prefix. After updating, redeploy the project.

Events are logged to Intercom but do not trigger any automated messages

Cause: Intercom's automated messages are set up separately in the Intercom dashboard — logging an event via the API does not automatically trigger messages unless you've configured message rules in Intercom that filter on that event.

Solution: In Intercom, go to Outbound Messages → New Message → Target users by behavior → Add filter → User did event → enter your event name. Set the timing and message content. Events you track via the API only trigger automated messages when matching rules exist in the Intercom dashboard. This is expected behavior — the API tracks the event, Intercom's rules engine decides what to do with it.

Best practices

  • Always boot Intercom with user identification data when a user is logged in — anonymous sessions make it difficult for support agents to connect chat conversations with user accounts
  • Use Intercom identity verification in production by passing a user_hash generated server-side — this prevents malicious users from impersonating other users in chat by spoofing user IDs
  • Track meaningful business events rather than every UI interaction — focus on events like 'feature_used', 'payment_completed', or 'onboarding_step_completed' that power useful Intercom segments and automated messages
  • Call window.Intercom('update') when user plan or key attributes change so support agents always see current user data without requiring a page reload
  • Store the Intercom App ID as NEXT_PUBLIC_INTERCOM_APP_ID (client-safe) and the access token as INTERCOM_ACCESS_TOKEN (server-only) — never expose the access token in client code
  • Handle the case where window.Intercom is undefined gracefully — the script may not load due to ad blockers, so use optional chaining (window.Intercom?.()) to prevent JavaScript errors
  • For high-traffic apps, throttle event tracking to avoid hitting Intercom's rate limits — batch events or debounce rapid sequential events before sending them to the API route

Alternatives

Frequently asked questions

Do I need to use the Intercom npm package or can I use the JavaScript snippet?

For embedding the Intercom Messenger widget, the vanilla JavaScript snippet loaded via a script tag is simpler and more reliable than npm packages. The @intercom/messenger-js-sdk package exists but adds bundle size. For server-side API calls in Next.js routes, use native fetch — the Intercom REST API is standard HTTP and doesn't require an SDK. This guide covers the fetch approach for both simplicity and bundle size efficiency.

Will Intercom work with Vercel's serverless functions?

Yes — Intercom API calls from Next.js API routes work perfectly on Vercel's serverless infrastructure. Outbound API calls to Intercom's REST API complete in well under Vercel's default timeout. The Messenger widget runs entirely in the browser and is unaffected by serverless limitations. For webhook receiving (Intercom sending events to your app), ensure your API route responds quickly with a 200 status before processing the payload asynchronously.

What is Intercom identity verification and do I need it?

Identity verification prevents users from impersonating each other by requiring each user's boot call to include a user_hash — an HMAC-SHA256 hash of the user ID signed with your Intercom Identity Verification Secret. Without it, any user could pass any user_id in their browser and access another user's conversation history. For production apps where user data privacy matters, identity verification is strongly recommended. Generate the hash server-side in a Server Action using Node.js's crypto module.

How do I build a custom chat UI instead of using the Intercom bubble?

Set hide_default_launcher: true in the Intercom boot call to remove the default bubble, then use the Intercom JavaScript API methods to control the widget programmatically — window.Intercom('show') to open it, window.Intercom('hide') to close it, and window.Intercom('showNewMessage', 'prefilled text') to open with a specific message. This lets you design your own 'Chat with us' button using V0's generated UI while still using Intercom's full messaging capabilities behind the scenes.

Can I use Intercom on the free plan for V0 app integrations?

Intercom does not offer a permanent free plan for businesses — there is a 14-day free trial. After the trial, paid plans start at around $39/month. For early-stage V0 apps with under 1,000 contacts, the Starter plan is usually sufficient. If budget is a constraint, Freshdesk and Crisp both offer free tiers with chat widget and basic API access that follow the same integration patterns described in this guide.

How do I receive Intercom webhook events in my Next.js app?

Create a Next.js API route at app/api/intercom/webhook/route.ts that handles POST requests. Configure the webhook URL in Intercom Settings → Developers → Webhooks with your deployed Vercel URL. Intercom supports webhooks for events like conversation.user.created, conversation.user.replied, and contact.created. Verify the X-Hub-Signature header in your route using the webhook secret from Intercom's webhook settings to confirm the request is genuine before processing it.

How do I create Intercom contacts when users sign up in my V0 app?

Create a server action or API route that calls POST https://api.intercom.io/contacts with the user's email, external_id (your internal user ID), name, role ('user'), and any custom attributes. Call this route from your sign-up success handler, after the user is created in your database. This ensures the contact exists in Intercom before the user loads the app and boots the Messenger widget, so their chat history is correctly associated with their contact record.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.