← Docs

Identify your users

By default Murphy talks to an anonymous visitor. If you tell it who is chatting, it answers with their account in hand: their plan, their seat count, when they signed up, whatever you pass.

Sign the user id on your server

Identity has to be signed, or anyone could open your widget and claim to be another customer. Sign the user id with a secret that never reaches the browser.

// Your server, where you already know who the user is.
import crypto from 'crypto';

const userHash = crypto
  .createHmac('sha256', process.env.MURPHY_IDENTITY_SECRET)
  .update(String(user.id))
  .digest('hex');

Pass userHash to the page along with the rest of the user.

Identify in the browser

window.EchoFox('identify', {
  userId: user.id, // the same id you signed
  user_hash: userHash, // the signature from your server
  name: user.name,
  email: user.email,
  attributes: {
    // anything your agent should know
    plan: 'growth',
    mrr: 240,
    signed_up_at: '2026-03-14',
    seats: 12,
  },
});

window.Murphy works as well. The historical EchoFox global is kept so no existing embed breaks after the rename, and both point at the same thing.

What attributes are for

Attributes are free-form, and Murphy reads them when answering. A customer on your enterprise plan asking about a limit should hear their limit, not the one from the pricing page. Pass whatever makes the answer specific.

They also make rules sharper. "Escalate anyone above $500 MRR who sounds like they are cancelling" needs the MRR to be there.

Anonymous visitors

Identity is optional and Murphy works fine without it. Returning anonymous visitors are remembered across sessions, so someone who asked yesterday does not start from nothing today. Signed identity is what lets Murphy speak about an account rather than in general.