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.

Developer
4 min read
By Laurent Schaffner
Updated March 20, 2025

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
  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? 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'
          }
        }
      }
    });
  }
}

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

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);
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);
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
});

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 test mode keys for development (check JWT claims to identify test vs production)

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?

Create test mode API keys from your dashboard. Test keys operate on isolated test data that won't affect production analytics. You can identify test vs production keys by decoding the JWT and checking the environment claim.

Sources

Last reviewed

This article was last reviewed on March 20, 2025.

About the Author

LS

Laurent Schaffner

Founder & Engineer at Linkbreakers

Passionate about building tools that help businesses track and optimize their digital marketing efforts. Laurent founded Linkbreakers to make QR code analytics accessible and actionable for companies of all sizes.