How can we help?

Identify signed-in users (identity verification)

When people sign in to your website or app, Talvo can know who they are. Their chats land on their own contact, with their name and email, instead of showing up as an anonymous "Visitor." Your team sees who they're talking to, and every chat from that person stays in one history.

This is called identity verification. Setting it up needs someone who can add a little code to your site. On WordPress or Shopify, that means pasting the code below.

Do you need it?

You need it only if people sign in to your site or app. If your site has no logins (a marketing site, a blog, a brochure site), skip this. Chats still work, and Talvo asks visitors for their email so you can reply.

You also need somewhere to run a few lines of server code. That rules out site builders that can't run server code, such as Webflow, Squarespace, Carrd, and Wix without Velo. On those sites chats still work normally; they just can't be tied to a logged-in account.

How it works

  1. Talvo gives you a secret that only you and Talvo know.
  2. When a signed-in user loads a page, your server uses the secret to make a userHash from their user ID.
  3. Your page passes the user ID, the userHash and (optionally) their name and email to the chat.
  4. Talvo makes the same hash. If they match, Talvo knows the visitor really is that user.

The hash is what makes this safe. Anyone can type a name or email into their own browser, but without your secret nobody can produce the right hash, so nobody can pretend to be one of your customers and see their chat history.

Step 1: Create your secret

  1. In Talvo, go to Settings → General → Identity verification.
  2. Click Create secret, then Reveal, and copy it. It starts with tiv_.
  3. Store it on your server, usually as an environment variable named TALVO_IDENTITY_SECRET in your hosting provider's settings.

Only owners and admins can see the secret. Treat it like a password: never put it in page code, JavaScript files or a public repository.

Step 2: Make the hash on your server

For each signed-in user, your server computes HMAC-SHA256 of their user ID with your secret, written as 64 lowercase hex characters. Use the code for your platform.

Node.js

Any Node server (Express, Next.js, Remix, NestJS and so on).

// Runs on your server, never in the browser.
const crypto = require("crypto");

function talvoUserHash(userId) {
  return crypto
    .createHmac("sha256", process.env.TALVO_IDENTITY_SECRET)
    .update(String(userId).trim())
    .digest("hex");
}

// When you render a page for a signed-in user:
const userHash = talvoUserHash(currentUser.id);

PHP

Laravel, Symfony or plain PHP.

<?php
// Runs on your server, never in the browser.
function talvo_user_hash($user_id) {
    return hash_hmac('sha256', trim((string) $user_id), getenv('TALVO_IDENTITY_SECRET'));
}

// When you render a page for a signed-in user:
$user_hash = talvo_user_hash($current_user->id);

WordPress

For WordPress sites with logged-in users. This one file does steps 2 and 3 for you.

<?php
/*
 * 1. In wp-config.php, above "That's all, stop editing!":
 *      define('TALVO_IDENTITY_SECRET', 'tiv_paste_your_secret_here');
 *
 * 2. Save THIS file as wp-content/mu-plugins/talvo-identity.php
 *    (create the mu-plugins folder if it doesn't exist).
 *    It runs automatically; there's nothing to activate.
 */
add_action('wp_head', function () {
    if (!is_user_logged_in() || !defined('TALVO_IDENTITY_SECRET')) {
        return;
    }
    $user = wp_get_current_user();
    $settings = [
        'userId'   => (string) $user->ID,
        'email'    => $user->user_email,
        'name'     => $user->display_name,
        'userHash' => hash_hmac('sha256', (string) $user->ID, TALVO_IDENTITY_SECRET),
    ];
    echo '<script>window.TalvoSettings = ' . wp_json_encode($settings) . ';</script>' . "\n";
}, 1);

If you use a page-caching plugin, make sure it doesn't cache pages for logged-in users. Most don't by default.

Python

Django, Flask, FastAPI and so on.

# Runs on your server, never in the browser.
import hashlib
import hmac
import os

def talvo_user_hash(user_id):
    secret = os.environ["TALVO_IDENTITY_SECRET"].encode()
    return hmac.new(secret, str(user_id).strip().encode(), hashlib.sha256).hexdigest()

# When you render a page for a signed-in user:
user_hash = talvo_user_hash(request.user.id)

Ruby

Rails, Sinatra and so on.

# Runs on your server, never in the browser.
require "openssl"

def talvo_user_hash(user_id)
  OpenSSL::HMAC.hexdigest("SHA256", ENV.fetch("TALVO_IDENTITY_SECRET"), user_id.to_s.strip)
end

# When you render a page for a signed-in user:
user_hash = talvo_user_hash(current_user.id)

C# / .NET

ASP.NET Core on .NET 6 or newer.

// Runs on your server, never in the browser. .NET 6 or newer.
using System.Security.Cryptography;
using System.Text;

static string TalvoUserHash(string userId)
{
    var secret = Encoding.UTF8.GetBytes(Environment.GetEnvironmentVariable("TALVO_IDENTITY_SECRET")!);
    var hash = HMACSHA256.HashData(secret, Encoding.UTF8.GetBytes(userId.Trim()));
    return Convert.ToHexString(hash).ToLowerInvariant();
}

// When you render a page for a signed-in user:
var userHash = TalvoUserHash(currentUser.Id.ToString());

Shopify

For stores with customer accounts. Paste this into your theme; it also does step 3.

{%- comment -%}
  Online Store → Themes → … → Edit code → layout/theme.liquid.
  Paste this inside <head>, ABOVE the Talvo script tag.
  Replace tiv_paste_your_secret_here with your secret.
{%- endcomment -%}
{%- if customer -%}
  {%- assign talvo_user_id = customer.id | append: '' -%}
  <script>
    window.TalvoSettings = {
      userId: {{ talvo_user_id | json }},
      email: {{ customer.email | json }},
      name: {{ customer.name | json }},
      userHash: {{ talvo_user_id | hmac_sha256: 'tiv_paste_your_secret_here' | json }}
    };
  </script>
{%- endif -%}

Shopify runs this on its own servers, so shoppers only ever see the hash. Keep in mind that anyone who can edit your theme can see the secret.

Check your code with this example

Before going live, run your code with this example secret and user ID. If you get exactly this hash, your code is right.

  • Secret: tiv_example_0123456789abcdef
  • User ID: 42
  • Correct userHash: fd5fa2613a06f46a651b5845c97900ca965c29b5e3d7d381cf8c7bae944553f7

This example secret isn't a real one. Swap in your own secret afterward.

Step 3: Pass it to the chat

On pages where someone is signed in, set window.TalvoSettings before your Talvo script tag:

<!-- Only on pages where someone is signed in. Fill the values from your server. -->
<script>
  window.TalvoSettings = {
    userId: "42",            // your own id for this user, as text
    email: "jo@example.com", // optional: shown to your team
    name: "Jo Rivera",       // optional
    userHash: "fd5fa261…"    // from step 2 (64 characters)
  };
</script>

<!-- Your existing Talvo script stays where it is, AFTER the block above: -->
<script async src="https://talvo.chat/_api/widget/loader?app=YOUR_APP_ID"></script>
  • userId must be exactly the text your server signed. Use your own permanent ID for the user, not something that changes, like a session ID.
  • email and name are optional. They show on the contact for your team.
  • Replace YOUR_APP_ID with the ID in your existing Talvo script (it's also shown in Settings).
  • Leave the block out entirely for visitors who aren't signed in.

Single-page apps (React, Vue, Angular and so on)

If people sign in or out without a page reload, tell Talvo when it happens:

// 1. Once, before the Talvo script tag, so early calls wait in a queue:
window.Talvo = window.Talvo || function () { (window.Talvo.q = window.Talvo.q || []).push(arguments); };

// 2. After someone signs in (fetch userHash from your server):
Talvo("identify", { userId: "42", email: "jo@example.com", name: "Jo Rivera", userHash });

// 3. After they sign out:
Talvo("logout");

If someone signs in partway through a chat, Talvo moves that chat onto their contact. After Talvo("logout"), or when a different user signs in, the chat starts fresh in that browser, so the next person never sees the previous person's messages.

Step 4: Test it

  1. Go back to Settings → General → Identity verification. In Test it, paste a real user ID and the hash your server made for it, then click Check. Talvo tells you whether the hash is right and, if it isn't, what to fix.
  2. Sign in to your own site, open the chat and send a message.
  3. In your Talvo inbox, the chat should show your name and email instead of "Visitor."
  4. The status line in Settings turns green and shows the latest recognized customer.

Troubleshooting

The chat still says "Visitor." Check, in order:

  • Your page sets window.TalvoSettings before the Talvo script tag. Talvo reads it once, when the script loads. If your app learns who's signed in later, use Talvo("identify", ...) instead.
  • The secret on your server is the current one. If you rotated it in Settings, the old one stopped working immediately.
  • userId on the page is exactly what your server signed: same characters, same capitalization, no extra spaces. A number like 42 is fine; Talvo reads it as the text 42.
  • You deployed the server change. Some hosts need a redeploy before a new environment variable takes effect.

The checker says "base64." Your code is producing the right hash in the wrong format. Output hex instead: digest("hex") in Node, hexdigest() in Python. PHP's hash_hmac already returns hex.

The checker says there's an extra space or the capitalization differs. Sign the ID exactly as you pass it to the page. Trim it first.

The checker says the hash wasn't made with your current secret. Re-copy the secret from Settings into your server's settings, redeploy, and check that you're signing the same ID you pass to the page.

One user's name showed up for another user. A cache is serving one person's page to others. Exclude signed-in pages from page caching, or set TalvoSettings in a part of the page that isn't cached.

Good to know

  • No user ID? You can sign the email address instead and leave out userId. Sign the email exactly as you pass it, including its capitalization.
  • Without a valid hash, Talvo treats the visitor as anonymous. It only uses the email to pre-fill the "where should we reply" box, exactly as if the visitor had typed it.
  • Rotate the secret only if it may have leaked. The old secret stops working at once, so signed-in visitors show as anonymous until your server uses the new one.
  • Identity verification covers the website chat widget. Contacts you create through the REST API or by email are matched by email address, as before.