Show customer data
to your support team
When a widget user sends their first message, Talki calls your backend endpoint to fetch their profile — name, email, plan, and any custom fields. Operators see it live in the ticket panel. No polling, no manual lookups.
How it works
Widget user sends first message — Talki fires a POST to your endpoint
Your endpoint verifies the HMAC-SHA256 signature and returns user JSON
Talki saves the data and shows it to operators — instantly, in the sidebar
Operators can hit Refresh any time to re-fetch updated data
Enable Backend Connect in Admin
In your Talki Console, go to Admin → Backend Connect. Enter your endpoint URL and save — you'll receive a signing secret. Copy it now: it's shown only once.
Endpoint URL — the HTTPS URL Talki will POST to
User token field — key name for the visitor ID (default: userToken)
Signing secret — used to verify X-Talki-Signature on your server
Pass the user ID from your widget
When initializing the Talki widget, set visitorId to your logged-in user's unique identifier. Talki sends this value in the POST body so your backend can look up the right user.
<!-- Pass the logged-in user's ID so Talki can look them up -->
<script>
window.TalkiConfig = {
orgId: 'YOUR_ORG_ID',
apiKey: 'YOUR_PUBLIC_API_KEY',
visitorId: currentUser.id, // <-- your user's unique ID
};
</script>If you don't set visitorId, the widget still works — Backend Connect simply won't fire because there's no identifier to resolve.
Build your endpoint
Talki sends a signed POST request to your URL with this payload:
POST /your-endpoint
Content-Type: application/json
X-Talki-Signature: <hmac-sha256-hex>
{ "userToken": "<visitorId you passed to the widget>" }Your endpoint must respond within 5 seconds with a JSON object. All fields are optional — return whatever is useful:
{
"name": "Alice Johnson",
"email": "alice@example.com",
"plan": "pro",
"fields": {
"mrr": 149,
"company": "Acme Inc",
"signedUpAt":"2024-01-15"
}
}name, email, and plan get special treatment in the UI (plan renders as a badge). Anything inside fields is displayed as a key-value list — use it for any custom data.
Verify the signature
Always verify X-Talki-Signature before trusting the payload. Use the raw request body — not the parsed JSON — to compute the HMAC.
Node.js / Express
const crypto = require('crypto');
// Install: npm install express
app.post('/talki/customer', express.raw({ type: 'application/json' }), (req, res) => {
const sig = req.headers['x-talki-signature'];
const expected = crypto
.createHmac('sha256', process.env.TALKI_SECRET)
.update(req.body) // raw Buffer — do NOT use req.body after JSON.parse
.digest('hex');
if (!sig || sig !== expected) {
return res.status(401).json({ error: 'Invalid signature' });
}
const { userToken } = JSON.parse(req.body);
const user = await db.users.findById(userToken);
if (!user) return res.status(404).json({ error: 'User not found' });
res.json({
name: user.name,
email: user.email,
plan: user.plan, // shown as a pill badge
fields: { // any key-value pairs you want
mrr: user.mrr,
company: user.company,
signedUpAt: user.createdAt,
},
});
});Python / Flask
import hmac, hashlib, json
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route('/talki/customer', methods=['POST'])
def talki_customer():
sig = request.headers.get('X-Talki-Signature', '')
raw = request.get_data() # raw bytes before any parsing
expected = hmac.new(
os.environ['TALKI_SECRET'].encode(),
raw,
hashlib.sha256,
).hexdigest()
if not hmac.compare_digest(sig, expected):
return jsonify(error='Invalid signature'), 401
body = json.loads(raw)
user = db.get_user(body['userToken'])
return jsonify(
name=user.name,
email=user.email,
plan=user.plan,
fields={'mrr': user.mrr, 'company': user.company},
)hmac.compare_digest in Python, crypto.timingSafeEqual in Node.js) to prevent timing attacks.Rotate the secret (when needed)
In Admin → Backend Connect → Signing secret, click Rotate. Talki generates a new secret immediately — copy it, update your env var, then redeploy. Old requests signed with the previous secret will start failing once rotated.
Done — operators see it instantly
From now on, when a widget user with a visitorId sends their first message, your customer's name, email, plan, and any custom fields appear in the ticket sidebar within seconds. No page reload, no manual lookups.
Common questions
What if my endpoint is down or returns an error?
Talki retries once, then silently skips — the ticket still opens and the operator can manually hit Refresh in the customer panel when you're back up.
Can I return different fields for different users?
Yes. The fields object is flexible — return as many or as few keys as you like per user.
Is the signing secret the same as my API key?
No. The signing secret is used only for Backend Connect HMAC verification — it's separate from your public API key.
Can operators manually refresh the data?
Yes. There's a Refresh button in the App data section of the customer panel in every ticket.
