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…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.