Docs

Identity verification (SSO)

Recognize users who are already logged in to your app. They skip the name/email question, your team sees who they are, and verified users get their chat history on every device.

How it works

  1. Copy your secret key in Settings - Live chat - Identity verification.
  2. On your server, compute HMAC-SHA256(lowercase email, secret) as a hex string.
  3. On your website, pass the email and signature (plus any other details) with $cajobo.

Signed and valid: the visitor is linked to the existing contact with that email, including all earlier chats. Unsigned: details only prefill name and email and never unlock earlier chats. With Require verified identity on, unsigned details are ignored.

1. Add to your website

Push commands any time - before or after the widget script loads.

<script>
  window.$cajobo = window.$cajobo || [];
  // After your user logged in:
  $cajobo.push(["set", "user:email", [user.email, user.cajoboSignature]]);
  $cajobo.push(["set", "user:nickname", [user.name]]);
  $cajobo.push(["set", "user:avatar", [user.avatarUrl]]);     // https only
  $cajobo.push(["set", "user:company", [user.companyName]]);
  $cajobo.push(["set", "user:id", [user.id]]);
  $cajobo.push(["set", "session:data", [[["plan", "pro"], ["mrr", 49]]]]);
</script>
<script src="https://cajobo.com/widget.js" data-workspace="YOUR_WORKSPACE_ID" async></script>

Prefer a single object? Set it before the widget script:

<script>
  window.CAJOBO_USER = {
    email: "jan@acme.com",
    signature: "<HMAC from your server>",
    name: "Jan de Vries",
    avatar: "https://acme.com/jan.png",
    company: "Acme BV",
    user_id: "12345",
    data: { plan: "pro", mrr: 49 }
  };
</script>

2. Create the signature on your server

Never compute the signature in the browser - anyone could then impersonate your users.

Node.js

import crypto from "crypto";

const signature = crypto
  .createHmac("sha256", process.env.CAJOBO_IDENTITY_SECRET)
  .update(user.email.toLowerCase())
  .digest("hex");

PHP

$signature = hash_hmac(
  'sha256',
  strtolower($user->email),
  getenv('CAJOBO_IDENTITY_SECRET')
);

Python

import hmac, hashlib, os

signature = hmac.new(
    os.environ["CAJOBO_IDENTITY_SECRET"].encode(),
    user.email.lower().encode(),
    hashlib.sha256,
).hexdigest()

Ruby

require "openssl"

signature = OpenSSL::HMAC.hexdigest(
  "SHA256",
  ENV["CAJOBO_IDENTITY_SECRET"],
  user.email.downcase
)

3. On logout

// On logout, forget the visitor so the next person starts fresh
$cajobo.push(["do", "session:reset"]);

All commands

$cajobo.push(["set", "user:email", [email, signature]])Email of the logged-in user. Add the signature to verify it.
$cajobo.push(["set", "user:nickname", [name]])Name shown to your team.
$cajobo.push(["set", "user:avatar", [url]])Profile picture (https URL).
$cajobo.push(["set", "user:company", [name]])Company name.
$cajobo.push(["set", "user:id", [id]])Your own user ID, shown in the inbox.
$cajobo.push(["set", "user:signature", [signature]])Set the signature separately.
$cajobo.push(["set", "session:data", [[[key, value], ...]]])Custom data (plan, MRR, ...) shown under Customer data. Max 50 keys.
$cajobo.push(["do", "session:reset"])Forget the visitor (call on logout).
$cajobo.push(["do", "chat:open"] / ["do", "chat:close"] / ["do", "chat:toggle"])Open or close the chat window.

Migrating from Crisp

The API follows Crisp's $crisp format, so most code works by renaming $crisp to $cajobo. Replace your Crisp identity secret with your Cajobo secret key.

CrispCajobo
$crisp.push(["set", "user:email", [email, signature]])$cajobo.push(["set", "user:email", [email, signature]])
$crisp.push(["set", "user:nickname", [name]])$cajobo.push(["set", "user:nickname", [name]])
$crisp.push(["set", "user:avatar", [url]])$cajobo.push(["set", "user:avatar", [url]])
$crisp.push(["set", "user:company", [name]])$cajobo.push(["set", "user:company", [name]])
$crisp.push(["set", "session:data", [[[k, v]]]])$cajobo.push(["set", "session:data", [[[k, v]]]])
$crisp.push(["do", "session:reset"])$cajobo.push(["do", "session:reset"])
$crisp.push(["do", "chat:open"])$cajobo.push(["do", "chat:open"])
CRISP_TOKEN_IDNot needed - verified email links history

Questions? Email hi@cajobo.com.