---
title: "Linkbreakers TypeScript SDK: Complete Integration Guide"
description: "Learn how to integrate the Linkbreakers TypeScript/JavaScript SDK for both frontend visitor tracking and backend link management. Includes publishable vs secret key differences, authentication, and real code examples."
canonical: "https://linkbreakers.com/help/article/typescript-sdk-quickstart"
last-updated: 2026-10-11
---

# Linkbreakers TypeScript SDK: Complete Integration Guide

> Learn how to integrate the Linkbreakers TypeScript/JavaScript SDK for both frontend visitor tracking and backend link management. Includes publishable vs secret key differences, authentication, and real code examples.

## Short answer

The Linkbreakers TypeScript SDK enables programmatic link management, visitor identification, and analytics access from your TypeScript and JavaScript applications. It supports two integration modes: frontend visitor tracking with publishable keys (safe for browsers) and backend operations with secret keys (server-side only). Install with `npm install linkbreakers` and choose the appropriate key type for your use case.

## Installation

Install the SDK using your preferred package manager:

```bash
# Using pnpm (recommended)
pnpm add linkbreakers

# Using npm
npm install linkbreakers

# Using yarn
yarn add linkbreakers
```

## Understanding API key types

Linkbreakers provides two types of API keys for different security contexts:

### Publishable keys

**Safe for frontend/browser use.** These JWT tokens can be embedded in client-side code without security concerns.

**What they allow:**
- Identify visitors (associate user data with sessions)
- Track visitor behavior and attributes
- Read visitor profiles

**What they DON'T allow:**
- Create or manage links
- Access workspace-level data
- View analytics or metrics
- Modify workspace settings

**When to use:** Frontend applications, mobile apps, browser extensions, or any environment where the key could be exposed publicly.

### Secret keys

**Backend-only.** These JWT tokens grant full API access and must never be exposed in client-side code.

**What they allow:**
- Everything publishable keys can do, plus:
- Create, update, and delete links
- Generate QR codes
- Access analytics and metrics
- Manage workspace resources
- Full API access

**When to use:** Server-side applications, API routes, serverless functions, CI/CD pipelines, or any secure backend environment.

## Creating API keys

Create your API keys from the dashboard:

1. Log in to [app.linkbreakers.com](https://app.linkbreakers.com)
2. Navigate to **Dashboard → API Tokens**
3. Click **Create API Token**
4. Choose the key type:
   - **Publishable Key** for frontend visitor tracking
   - **Secret Key** for backend link management
5. Give it a descriptive name (e.g., "Production Frontend" or "Backend API")
6. Copy the generated key immediately (you won't see it again)

**Security best practice:** Use environment variables for both key types. While publishable keys are safe to expose, storing them in env vars makes key rotation easier.

## Frontend usage: Visitor tracking

Use publishable keys to identify visitors when they sign up, log in, or interact with your application.

### Basic visitor identification

```typescript
import { Configuration, VisitorsApi } from 'linkbreakers';

// ✅ SAFE FOR FRONTEND - Using publishable key (JWT token)
const config = new Configuration({
  accessToken: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',  // Publishable JWT token
  basePath: 'https://api.linkbreakers.com',
});

const visitorsApi = new VisitorsApi(config);

// Extract LBID from URL (comes from link clicks with conversion tracking)
const urlParams = new URLSearchParams(window.location.search);
const lbid = urlParams.get('lbid');

if (lbid) {
  // Identify the visitor with their data
  const response = await visitorsApi.visitorsServiceIdentify({
    identifyRequest: {
      lbid: lbid,
      visitor: {
        data: {
          // System fields (prefixed with "$")
          '$email': 'user@example.com',
          '$phone': '+1234567890',
          '$firstName': 'John',
          '$lastName': 'Doe',

          // Custom attributes (no "$" prefix)
          'plan': 'premium',
          'signupDate': '2024-01-15',
          'company': 'Acme Corp'
        }
      },
      setOnce: false  // If true, only sets empty fields (preserves existing data)
    }
  });

  console.log('New visitor profile:', response.created);
  console.log('Visitor ID:', response.visitor?.id);
}
```

### Understanding LBID (Linkbreakers ID)

When visitors click your Linkbreakers links with **conversion tracking enabled**, a query parameter `?lbid=...` is automatically added to the destination URL. This LBID connects the click event to the visitor, enabling powerful attribution and analytics.

**Where LBID comes from:**
- Query parameter when users click your short links: `?lbid=abc123`
- Tracking cookies set by Linkbreakers
- Webhook payloads for link interactions

Learn more in our [What is LBID?](/help/article/what-is-the-linkbreakers-id-lbid) guide.

### Form submission example

Track users who fill out forms on your landing page:

```typescript
// In your form handler
async function handleFormSubmit(formData) {
  const config = new Configuration({
    accessToken: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',  // Publishable JWT
    basePath: 'https://api.linkbreakers.com',
  });

  const visitorsApi = new VisitorsApi(config);
  const lbid = new URLSearchParams(window.location.search).get('lbid');

  if (lbid) {
    await visitorsApi.visitorsServiceIdentify({
      identifyRequest: {
        lbid: lbid,
        visitor: {
          data: {
            '$email': formData.email,
            '$firstName': formData.firstName,
            '$lastName': formData.lastName,
            'interest': formData.productInterest,
            'source': 'landing-page-form'
          }
        }
      }
    });
  }
}
```

## Backend usage: Link management

Use secret keys on your backend to create and manage links programmatically.

### Creating your first link

```typescript
import { Configuration, LinksApi } from 'linkbreakers';

// ❌ NEVER USE IN FRONTEND - Secret key for backend only
const config = new Configuration({
  accessToken: process.env.LINKBREAKERS_SECRET_KEY,  // Secret JWT from env var
  basePath: 'https://api.linkbreakers.com',
});

const linksApi = new LinksApi(config);

// Create a shortened link
const response = await linksApi.linksServiceCreate({
  createLinkRequest: {
    destination: 'https://example.com/product',
    name: 'Product Launch Campaign',
    tags: ['marketing', 'spring-2025']
  }
});

console.log('Short URL:', response.link?.shortlink);
console.log('QR Code URL:', response.link?.qrcodeSignedUrl);
```

### Advanced link creation

```typescript
import { Configuration, LinksApi } from 'linkbreakers';

const config = new Configuration({
  accessToken: process.env.LINKBREAKERS_SECRET_KEY,
  basePath: 'https://api.linkbreakers.com',
});

const linksApi = new LinksApi(config);

// Create link with custom shortlink
const customLink = await linksApi.linksServiceCreate({
  createLinkRequest: {
    destination: 'https://example.com/docs',
    shortlink: 'docs',  // Creates lbr.ai/docs
    name: 'Documentation Home',
    tags: ['docs', 'internal'],
    metadata: {
      campaign_id: 'spring-2025',
      department: 'engineering'
    }
  }
});

// Create link with QR code (wait for generation)
const qrLink = await linksApi.linksServiceCreate({
  createLinkRequest: {
    destination: 'https://example.com/event',
    name: 'Conference Registration',
    waitForQrcode: true,  // Blocks until QR is ready
    tags: ['event', 'qr-code']
  }
});

console.log('Download QR:', qrLink.link?.qrcodeSignedUrl);
```

### Managing links

```typescript
import { Configuration, LinksApi } from 'linkbreakers';

const config = new Configuration({
  accessToken: process.env.LINKBREAKERS_SECRET_KEY,
  basePath: 'https://api.linkbreakers.com',
});

const linksApi = new LinksApi(config);

// List links with filtering
const listResponse = await linksApi.linksServiceList({
  pageSize: 50,
  tags: ['marketing'],
  search: 'campaign',
  sortBy: 'LINK_SORT_FIELD_UPDATED_AT',
  sortDirection: 'SORT_DIRECTION_DESC'
});

for (const link of listResponse.links || []) {
  console.log(`${link.name}: ${link.shortlink}`);
}

// Get specific link details
const linkResponse = await linksApi.linksServiceGet({
  id: 'your-link-uuid',
  include: ['tags', 'qrcodeSignedUrl']
});

// Update link
await linksApi.linksServiceUpdate({
  id: linkResponse.link?.id,
  updateLinkRequest: {
    name: 'Updated Campaign Name',
    tags: ['marketing', 'q2-2025']
  }
});

// Delete link
await linksApi.linksServiceDelete({
  id: linkResponse.link?.id
});
```

### Bulk link creation

Efficiently create multiple links in one API call:

```typescript
import { Configuration, LinksApi } from 'linkbreakers';

const config = new Configuration({
  accessToken: process.env.LINKBREAKERS_SECRET_KEY,
  basePath: 'https://api.linkbreakers.com',
});

const linksApi = new LinksApi(config);

const response = await linksApi.linksServiceCreateBulk({
  createBulkLinksRequest: {
    links: [
      {
        destination: 'https://example.com/product-1',
        name: 'Product 1',
        tags: ['catalog'],
        metadata: { sku: 'PROD-001' }
      },
      {
        destination: 'https://example.com/product-2',
        name: 'Product 2',
        tags: ['catalog'],
        metadata: { sku: 'PROD-002' }
      }
    ]
  }
});

console.log(`Created ${response.links?.length} links`);
```

## Accessing analytics

Retrieve events and metrics (requires secret key):

```typescript
import { Configuration, EventsApi, MetricsApi } from 'linkbreakers';

const config = new Configuration({
  accessToken: process.env.LINKBREAKERS_SECRET_KEY,
  basePath: 'https://api.linkbreakers.com',
});

const eventsApi = new EventsApi(config);
const metricsApi = new MetricsApi(config);

// Get events for a specific link
const endDate = new Date();
const startDate = new Date();
startDate.setDate(startDate.getDate() - 30);

const eventsResponse = await eventsApi.eventsServiceList({
  linkId: 'your-link-uuid',
  startDate: startDate.toISOString(),
  endDate: endDate.toISOString(),
  pageSize: 100,
  include: ['visitor', 'device']
});

// Get workspace metrics
const metrics = await metricsApi.metricsServiceGetWorkspaceMetrics();
console.log('Total clicks:', metrics.totalClicks);
```

## Framework integration examples

### Next.js (App Router)

**Frontend visitor tracking:**

```typescript
// app/components/visitor-tracker.tsx
'use client';

import { Configuration, VisitorsApi } from 'linkbreakers';
import { useEffect } from 'react';

export function VisitorTracker({ userEmail }: { userEmail: string }) {
  useEffect(() => {
    const config = new Configuration({
      accessToken: process.env.NEXT_PUBLIC_LINKBREAKERS_PK,  // Publishable JWT
      basePath: 'https://api.linkbreakers.com',
    });

    const visitorsApi = new VisitorsApi(config);
    const lbid = new URLSearchParams(window.location.search).get('lbid');

    if (lbid && userEmail) {
      visitorsApi.visitorsServiceIdentify({
        identifyRequest: {
          lbid,
          visitor: {
            data: { '$email': userEmail }
          }
        }
      });
    }
  }, [userEmail]);

  return null;
}
```

**Backend link creation:**

```typescript
// app/api/create-link/route.ts
import { Configuration, LinksApi } from 'linkbreakers';
import { NextResponse } from 'next/server';

export async function POST(request: Request) {
  const config = new Configuration({
    accessToken: process.env.LINKBREAKERS_SECRET_KEY,  // Secret JWT
    basePath: 'https://api.linkbreakers.com',
  });

  const linksApi = new LinksApi(config);
  const { destination, name } = await request.json();

  const response = await linksApi.linksServiceCreate({
    createLinkRequest: { destination, name }
  });

  return NextResponse.json({ shortlink: response.link?.shortlink });
}
```

### Node.js / Express

```typescript
import express from 'express';
import { Configuration, LinksApi } from 'linkbreakers';

const app = express();
app.use(express.json());

const config = new Configuration({
  accessToken: process.env.LINKBREAKERS_SECRET_KEY,
  basePath: 'https://api.linkbreakers.com',
});

app.post('/api/create-link', async (req, res) => {
  const linksApi = new LinksApi(config);

  const response = await linksApi.linksServiceCreate({
    createLinkRequest: {
      destination: req.body.destination,
      name: req.body.name
    }
  });

  res.json({ shortlink: response.link?.shortlink });
});

app.listen(3000);
```

## Security best practices

### Environment variables

Store both key types in environment variables:

```bash
# .env file
LINKBREAKERS_SECRET_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ3b3Jrc3BhY2VfaWQiOiIxMjM0IiwidHlwZSI6InNlY3JldCJ9...
NEXT_PUBLIC_LINKBREAKERS_PK=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ3b3Jrc3BhY2VfaWQiOiIxMjM0IiwidHlwZSI6InB1Ymxpc2hhYmxlIn0...
```

**Next.js note:** Prefix publishable keys with `NEXT_PUBLIC_` to make them available in the browser.

### Key usage matrix

| Operation | Publishable Key | Secret Key |
|-----------|----------------|------------|
| Identify visitors | ✅ Yes | ✅ Yes |
| Update visitor profiles | ✅ Yes | ✅ Yes |
| Create links | ❌ No | ✅ Yes |
| Delete links | ❌ No | ✅ Yes |
| View analytics | ❌ No | ✅ Yes |
| Access workspace metrics | ❌ No | ✅ Yes |

### Common security mistakes

❌ **DON'T:**
- Use secret keys in frontend code
- Commit keys to version control
- Share keys in screenshots or documentation
- Use production keys in development

✅ **DO:**
- Use publishable keys for all frontend operations
- Store secret keys in environment variables
- Rotate keys if accidentally exposed
- Use a separate workspace's token for development and CI

To let an AI agent drive the TypeScript SDK, or to use the MCP server instead, see [How Linkbreakers works with AI agents](/help/article/linkbreakers-for-ai-agents).

## Frequently asked questions

**Can I use one key for both frontend and backend?**

No. Always use publishable keys (with limited scopes) for frontend and secret keys (with full access) for backend. Publishable keys have restricted permissions encoded in the JWT and cannot create links or access sensitive data.

**How do I enable conversion tracking to get LBID in URLs?**

In your link settings, enable "Conversion Tracking" on the redirect workflow step. This appends `?lbid=...` to destination URLs, enabling visitor attribution.

**Does the SDK work in the browser?**

Yes, but only use it with publishable keys. Never expose secret keys in client-side code.

**How do I handle rate limits?**

The SDK will throw errors if you exceed rate limits. Implement retry logic with exponential backoff for production applications.

**Can I use this with TypeScript?**

Yes! The SDK is written in TypeScript and includes full type definitions for autocomplete and type safety.

**What about test mode?**

There is no separate test mode. Use a [separate workspace](/help/article/work-across-multiple-workspaces) for development and CI, with its own API token, so tests never touch your live links or analytics. Tag test links so they are easy to find and delete.

## Sources

- [Linkbreakers TypeScript SDK GitHub Repository](https://github.com/linkbreakers-com/linkbreakers-typescript)
- [Linkbreakers TypeScript SDK on npm](https://www.npmjs.com/package/linkbreakers)
- [What is LBID?](https://linkbreakers.com/help/article/what-is-the-linkbreakers-id-lbid)
- [Linkbreakers API Documentation](https://linkbreakers.com/help/article/how-to-use-the-linkbreakers-api)

## Last reviewed

This article was last reviewed on March 20, 2025.
