Skip to content
Back to skills

Intercom

ASecurity

Adds customer messaging and support to a product with Intercom: the Messenger chat widget, user identification, product tours, help center, and the REST API for contacts and messages. Use when a user asks to add in-app chat, install Intercom in a React or Next.js app, secure the Messenger with JWTs, track events for targeting, sync users to Intercom from a backend, or send in-app messages.

  • 142 stars
  • 0 votes
  • 0 copies
  • 3 views
  • Added May 29, 2026
developmentjavascripttypescriptgojavabashreactnextjsnodeapibackend

Works with

  • terminal
  • cli
  • api

Security analysis

A96/100
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro scans all 2 files and shows the line behind each finding

Scanned October 4, 2026

npx -y skills add TerminalSkills/skills --skill intercom --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Intercom?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Intercom
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/terminalskills-intercom/badge)](https://www.skillsdirectory.com/skills/terminalskills-intercom)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: intercom
description: >-
  Adds customer messaging and support to a product with Intercom: the Messenger chat widget, user identification, product tours, help center, and the REST API for contacts and messages. Use when a user asks to add in-app chat, install Intercom in a React or Next.js app, secure the Messenger with JWTs, track events for targeting, sync users to Intercom from a backend, or send in-app messages.
license: Apache-2.0
compatibility: "Intercom workspace; web apps (JavaScript snippet or @intercom/messenger-js-sdk), iOS, Android; Node.js 18+ for the server examples"
metadata:
  author: terminal-skills
  version: "1.1.0"
  category: business
  tags: ["intercom", "chat", "support", "onboarding", "messaging"]
---

# Intercom

## Overview

Intercom is a customer messaging platform: live chat, a shared inbox, help center, product tours, in-app messages and the Fin AI agent. Two integration surfaces matter to developers. The **Messenger** runs in the browser (or iOS/Android) and shows the chat widget for a visitor or logged-in user. The **REST API** (`https://api.intercom.io`) runs on your server to manage contacts, conversations and messages with an access token.

Checked against the Intercom developer docs in October 2026. Two older practices are outdated: the HMAC `user_hash` identity verification is deprecated in favour of JWTs (`intercom_user_jwt`), and a hand-pasted loader snippet is no longer needed in React apps because the `@intercom/messenger-js-sdk` package loads the widget.

## Instructions

### Step 1: Install the Messenger in a React or Next.js app

Your workspace ID (`app_id`) is in the Intercom URL after `apps/`. It is public, so a `NEXT_PUBLIC_` variable is fine.

```bash
npm install @intercom/messenger-js-sdk
```

```tsx
// components/IntercomProvider.tsx
'use client'
import { useEffect } from 'react'
import Intercom, { shutdown } from '@intercom/messenger-js-sdk'

type Props = {
  user?: { id: string; email: string; name: string; createdAt: number; intercomJwt: string }
}

export function IntercomProvider({ user }: Props) {
  useEffect(() => {
    Intercom({
      app_id: process.env.NEXT_PUBLIC_INTERCOM_APP_ID!,
      // api_base: 'https://api-iam.eu.intercom.io',   // EU-hosted workspaces; AU: api-iam.au.intercom.io
      ...(user && {
        user_id: user.id,
        name: user.name,
        email: user.email,
        created_at: user.createdAt,          // Unix seconds
        intercom_user_jwt: user.intercomJwt, // signed on your server, see Step 2
      }),
    })
    return () => shutdown()                  // clears the session; also call on logout
  }, [user?.id])

  return null
}
```

Other exports of the package: `update`, `trackEvent`, `show`, `hide`, `showNewMessage`, `startTour`, `showArticle`. The plain `window.Intercom('boot' | 'update' | 'trackEvent' | 'shutdown', ...)` API works the same if you use the JavaScript snippet instead. Anonymous visitors: boot with only `app_id`.

### Step 2: Secure the Messenger with a JWT

Without verification anyone can impersonate a user by changing `user_id` in the browser. Take the Messenger secret key from Settings, Messenger, Security, keep it as `INTERCOM_MESSENGER_SECRET`, and sign a token on the server for the logged-in user.

```typescript
// app/api/intercom-jwt/route.ts — server only
import jwt from 'jsonwebtoken'

export function signIntercomJwt(user: { id: string; email: string; name: string }) {
  return jwt.sign(
    { user_id: user.id, email: user.email, name: user.name },   // user_id is required
    process.env.INTERCOM_MESSENGER_SECRET!,
    { algorithm: 'HS256', expiresIn: '1h' },
  )
}
```

Send exactly one of `intercom_user_jwt` or `user_hash`; both together returns HTTP 400. After tests pass, enforce verification in the Messenger security settings.

### Step 3: Track events and update on navigation

```typescript
import { trackEvent, update } from '@intercom/messenger-js-sdk'

update()                                                  // after a client-side route change
trackEvent('completed-onboarding', { plan: 'pro', team_size: 5 })   // targets tours, messages, workflows
```

### Step 4: Server-side API

Create a token under Developer Hub, then use a version header so behaviour does not change under you. Regional workspaces use `api.eu.intercom.io` or `api.au.intercom.io`.

```typescript
const headers = {
  'Content-Type': 'application/json',
  Authorization: `Bearer ${process.env.INTERCOM_ACCESS_TOKEN}`,
  'Intercom-Version': '2.16',
}

// Create a contact (a user needs an email or an external_id)
const contact = await fetch('https://api.intercom.io/contacts', {
  method: 'POST',
  headers,
  body: JSON.stringify({
    role: 'user',
    external_id: 'usr_8f31c2',
    email: 'maria.keller@brightdesk.io',
    name: 'Maria Keller',
    custom_attributes: { plan: 'pro', mrr: 49, company_size: 10 },
  }),
}).then((r) => r.json())

// Send an in-app message from an admin to that contact
await fetch('https://api.intercom.io/messages', {
  method: 'POST',
  headers,
  body: JSON.stringify({
    message_type: 'inapp',
    from: { type: 'admin', id: '394051' },
    to: { type: 'user', id: contact.id },
    body: 'Hi Maria, how are you finding the new dashboard?',
  }),
})
```

Creating a contact and messaging it immediately can return 404 for a moment; retry after a short delay. The official Node client is `intercom-client` (`new IntercomClient({ token })`), which has typed methods for the same endpoints. Custom attributes must exist as data attributes in the workspace to be used for segmentation.

## Examples

### Example 1: Add chat to a Next.js SaaS for logged-in users

Request: "Put the Intercom chat widget in our Next.js app and make sure users can't spoof each other."

Install `@intercom/messenger-js-sdk`, add `IntercomProvider` to the root layout inside the authenticated area, add the server function `signIntercomJwt`, pass its output as `intercomJwt`, then turn on "Enforce identity verification" in Messenger settings.

Result: the widget appears bottom-right; the user's name and email show in the Intercom inbox, and a request without a valid `intercom_user_jwt` is rejected.

### Example 2: Sync plan changes and tag power users

Request: "When someone upgrades to Pro, update their Intercom contact and record an event."

On the Stripe webhook handler, call the Contacts API (`PUT /contacts/{id}` with `custom_attributes: { plan: 'pro' }`) and fire `trackEvent('upgraded-to-pro', { seats: 5 })` from the client after checkout. Build a segment on `plan = pro`.

Result: the contact shows `plan: pro` in Intercom and the tour or message targeted at that segment starts for the next session.

## Guidelines

- Never put `INTERCOM_ACCESS_TOKEN` or the Messenger secret in client code; only `app_id` is public.
- Always call `shutdown()` on logout so the next person on a shared browser does not see the previous conversation.
- Pricing is per seat plus usage for the Fin AI agent and changes often; check intercom.com/pricing. Cheaper or self-hosted options are Crisp and Chatwoot.
- Rate limits apply to the API (HTTP 429); batch contact syncs and back off.
- Do not set identity-sensitive attributes (plan, role) from the browser; set them through the signed JWT or the server API.
- Intercom is not the tool for a plain status page or transactional email; use a dedicated service for those.

Files in this skill

  • SKILL.md3.7 KB
  • _scores.json1.9 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…