Matomo identifies visitors using first-party cookies stored in the browser. Because browsers and apps do not share first-party cookies, when a visitor continues their journey in a different browser or app, Matomo recognises the activity as a new visitor rather than a continuation of the existing journey.

This guide explains how to use the visitor ID and user ID to continue tracking the visitor journey across different websites, browsers, and apps.

When to use the Visitor and User ID

Visitor ID

Use the Visitor ID when you need to continue an anonymous journey before the visitor authenticates.

You will need to configure your application to transfer the existing Visitor ID and call setVisitorId() before the first tracking request in the new browser or app. This is only required at the handoff point.

Matomo then stores that Visitor ID in the new browser’s first-party cookie. Subsequent page loads use the cookie automatically, so you do not need to call setVisitorId() on every page.

User ID

If your application has a stable authenticated account identifier, it is recommended to use the User ID for cross-browser and device tracking.

When setUserId() is applied consistently across all browsers, websites, and apps, Matomo associates activity with the same user without manually transferring the Visitor ID.

Learn how to set up User ID tracking in Matomo.

Privacy considerations

Do not expose the Visitor ID in URLs. URLs can be stored in browser history, server logs, analytics logs, and proxy logs, and may be shared through the Referer header. Instead, use a short-lived token and retrieve the Visitor ID securely from your backend. Refer to the User ID privacy considerations guide.

If you use the CNIL privacy configuration, some visitor-level information and reports may be restricted. Refer to the CNIL configuration guide for details.

Transfer a Visitor ID between browsers and apps

When a visitor switches browsers or apps, the new environment cannot access the original Matomo visitor cookie. To continue the same anonymous visitor journey, your application must retrieve the original Visitor ID before the first tracking request.

This example uses a registration and email verification workflow. A visitor registers on your website in one browser, then opens the verification link in another browser, app, or device.

You can implement this workflow using the JavaScript tracking code or Matomo Tag Manager. Read the section below that is relevant to your setup.

Use the JavaScript tracking code

When a visitor begins registering on your website in one browser, read the current Visitor ID in the browser:

window._paq = window._paq || [];

window._paq.push([function () {
    const visitorId = this.getVisitorId();

    sendVerificationRequest(visitorId);
}]);

Send the Visitor ID to your backend. Treat this like any other session identifier: use an authenticated endpoint, transmit over HTTPS, and expire the token after a short window, for example:

async function sendVerificationRequest(visitorId) {
    const email = document.getElementById('email').value;

    const response = await fetch('/send-verification-email.php', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json'
        },
        body: JSON.stringify({
            email: email,
            visitorId: visitorId
        })
    });

    const result = await response.json();

    document.getElementById('verification-result').innerHTML =
        `<a href="${result.verificationUrl}">
            ${result.verificationUrl}
        </a>`;
}

Associate the Visitor ID with a short-lived verification token:

$visitorId = strtolower($data['visitorId'] ?? '');

if (!preg_match('/^[0-9a-f]{16}$/', $visitorId)) {
    http_response_code(400);
    echo json_encode(['error' => 'Invalid Matomo Visitor ID.']);
    exit;
}

Include the token generation:

$token = bin2hex(random_bytes(32));
$tokenHash = hash('sha256', $token);
$expiresAt = time() + 600;

$tokenData = [
    'email' => $email,
    'visitorId' => $visitorId,
    'expiresAt' => $expiresAt
];

Add the server-side storage code and then build the URL with only the token. The Visitor ID is stored server-side and is not included in the URL:

$verificationUrl =
    'https://example.com/verify.php?token=' .
    rawurlencode($token);

The visitor receives the verification link with a short-lived token:

{
  "expiresInSeconds": 600,
  "verificationUrl": "https://example.com/verify.php?token=22e01819b17e5cf0fcf6bb44b3487d235fc441e22e4aa34b3961d37dfcd2da55"
}

When the visitor clicks on the link in a different browser or application, your backend retrieves and applies the Visitor ID in the second browser.

Initialise the Matomo tracker before sending any tracking requests.

<script>
    window.history.replaceState({}, document.title, '/verify.php');

    window._paq = window._paq || [];

    window._paq.push([
        'setVisitorId',
        <?php echo json_encode($visitorId); ?>
    ]);

    window._paq.push([
        'setCustomUrl',
        'https://example.com/verify.php'
    ]);

    window._paq.push(['setDocumentTitle', 'Email verified']);
    window._paq.push(['trackPageView']);
</script>

In the original browser, this.getVisitorId() retrieves the existing Visitor ID. In the second browser, setVisitorId applies that ID before tracking.

Use Matomo Tag Manager

Your application must retrieve the Visitor ID from the backend before the first tracking request. Matomo Tag Manager does not store or transfer Visitor IDs between browsers or apps automatically.

After validating the verification token, retrieve the associated Visitor ID and make it available to the page by pushing the Visitor ID into the data layer (before the Matomo Tag Manager container snippet):

<script>
window._mtm = window._mtm || [];
window._mtm.push({
    transferredVisitorId: visitorId
});
</script>
  1. Open your Tag Manager container and select Variables.
  2. Create a new Data Layer Variable and provide a name, for example, Transferred Visitor ID.
  3. Configure the variable and set the Data Layer Variable Name to transferredVisitorId.
  4. Save the variable.
  5. Go to Tags and create a new Custom HTML tag with a Pageview trigger.
  6. To ensure the Custom HTML tag fires before the Matomo Analytics tracking tag, set the tag to a higher priority (lower number) than the Matomo tag.
  7. In the Custom HTML field, add the following code:
<script>
var visitorId = {{Transferred Visitor ID}};

if (visitorId) {
    window._paq = window._paq || [];
    window._paq.push(['setVisitorId', visitorId]);
}
</script>

Optional: After tracking the verification page, you can also track a custom event, such as Email Verification / Verified, to measure successful email verifications separately from page views.

Test the tracking setup

  • For Matomo Tag Manager, open the container in Preview / Debug mode.
  • For the JavaScript tracking code, use your browser’s developer tools.

Test both the original browser and the new browser or app to confirm that Matomo continues the same anonymous visitor journey.

  1. Test the implementation and start on one browser.
  2. Generate the verification link and open it in another browser, app, or browser profile.
  3. Navigate to another page without transferring or setting the Visitor ID again.
    view visit log
  4. Confirm that the next tracking request uses the same Visitor ID. This verifies that Matomo stored the transferred ID in the new browser’s first-party cookie and continued tracking normally.

Troubleshooting

If the first request uses a different Visitor ID, check the following:

  • The token returned the correct Visitor ID;
  • setVisitorId() ran before the first tracking request;
  • The Custom HTML tag executed before the Matomo tracking tag.
  • In Tag Manager Preview / Debug mode, check the resolved value of the Transferred Visitor ID variable and the order in which the tags execute.