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.