Skip to main content
This template connects Qminder to your CRM and automatically labels VIP customers when they check in.

What It Does

The template listens for visitor check-ins across all Qminder locations. When someone checks in, it queries your CRM to check if they’re a VIP. If they are, it applies a “VIP” label to their ticket.

Prerequisites

Before getting started, you’ll need:
  • Qminder API key - Create one in Qminder Dashboard under Organization Settings → Developer Tools. See Authentication for details.
  • Docker (recommended) OR Node.js 20+ with Yarn
  • CRM access - Credentials for your CRM system (Salesforce, HubSpot, or custom)

Quick Start

Clone the Repository

git clone https://github.com/Qminder/crm-integration-template.git
cd crm-integration-template
docker build -t crm-integration .
docker run -e API_KEY=your_qminder_api_key crm-integration

Option 2: Run with Node.js

yarn install
API_KEY=your_qminder_api_key yarn start
Once running, the template logs that it’s listening for visitor events.

How It Works

The template uses Qminder’s GraphQL API to subscribe to real-time events:
  1. Connects to Qminder - Establishes a WebSocket connection using your API key
  2. Subscribes to check-ins - Listens for the createdTickets subscription across all locations
  3. Extracts visitor info - When a ticket is created, extracts the visitor’s name, phone number, and email
  4. Queries your CRM - Calls your custom checkVip() function to look up the customer
  5. Applies the label - If the customer is a VIP, adds a “VIP” label to their Qminder ticket

Customization

Edit src/crm.ts to connect to your CRM. This file contains the checkVip() function.

The Interface

export async function checkVip(visitor: Visitor): Promise<boolean> {
  // Your CRM lookup logic here
  // Return true if VIP, false otherwise
}
The Visitor object contains:
  • firstName - Visitor’s first name
  • lastName - Visitor’s last name
  • phoneNumber - Phone number (if provided)
  • email - Email address (if provided)

Example: Salesforce Integration

import jsforce from 'jsforce';

const conn = new jsforce.Connection({
  loginUrl: 'https://login.salesforce.com'
});

await conn.login(process.env.SF_USERNAME, process.env.SF_PASSWORD);

export async function checkVip(visitor: Visitor): Promise<boolean> {
  const result = await conn.query(
    `SELECT Id, VIP__c FROM Contact
     WHERE Name = '${visitor.firstName} ${visitor.lastName}'
     LIMIT 1`
  );

  if (result.records.length > 0) {
    return result.records[0].VIP__c === true;
  }
  return false;
}

Example: HubSpot Integration

import { Client } from '@hubspot/api-client';

const hubspot = new Client({ accessToken: process.env.HUBSPOT_TOKEN });

export async function checkVip(visitor: Visitor): Promise<boolean> {
  const response = await hubspot.crm.contacts.searchApi.doSearch({
    filterGroups: [{
      filters: [{
        propertyName: 'firstname',
        operator: 'EQ',
        value: visitor.firstName
      }, {
        propertyName: 'lastname',
        operator: 'EQ',
        value: visitor.lastName
      }]
    }],
    properties: ['vip_status']
  });

  if (response.results.length > 0) {
    return response.results[0].properties.vip_status === 'true';
  }
  return false;
}

Example: Custom Database

import { Pool } from 'pg';

const pool = new Pool({
  connectionString: process.env.DATABASE_URL
});

export async function checkVip(visitor: Visitor): Promise<boolean> {
  const result = await pool.query(
    'SELECT is_vip FROM customers WHERE phone = $1 OR email = $2',
    [visitor.phoneNumber, visitor.email]
  );

  return result.rows[0]?.is_vip === true;
}

Project Structure

src/
├── app.ts          # Main entry point - sets up the Qminder listener
├── crm.ts          # Your CRM integration logic (customize this file)
└── model/ticket.ts # TypeScript type definitions for visitor data

Configuration

Environment VariableRequiredDescription
API_KEYYesYour Qminder REST API key
Add any CRM-specific environment variables your integration needs (e.g., SF_USERNAME, HUBSPOT_TOKEN, DATABASE_URL).

Deployment

Docker (Production)

docker build -t crm-integration .
docker run -d \
  -e API_KEY=your_qminder_api_key \
  -e HUBSPOT_TOKEN=your_hubspot_token \
  --restart unless-stopped \
  crm-integration

Cloud Platforms

The Docker image can be deployed to any container platform:
  • AWS - ECS, Fargate, or App Runner
  • Google Cloud - Cloud Run or GKE
  • Azure - Container Instances or AKS
  • Heroku - Container Registry

Process Managers

If running directly on a VM without Docker, use a process manager like PM2:
npm install -g pm2
API_KEY=your_key pm2 start yarn --name crm-integration -- start

Troubleshooting

Template not receiving events

  • Verify your API key is valid and has access to locations
  • Check that the WebSocket connection is established (look for connection logs)
  • Ensure your firewall allows outbound WebSocket connections

VIP labels not appearing

  • Confirm your checkVip() function returns true for test customers
  • Check the template logs for any CRM query errors
  • Verify the “VIP” label exists in your Qminder location settings

CRM connection issues

  • Double-check your CRM credentials in environment variables
  • Ensure your CRM API rate limits aren’t being exceeded
  • Test your CRM queries independently before integrating

Source Code

The full source code is available on GitHub: Qminder/crm-integration-template

Getting Help

Contact Qminder support for assistance. Enterprise plan customers have access to premium API support.