Отслеживание конверсий доступно на тарифе Business и выше .
В отслеживании конверсий событие lead — это
действие, которым пользователь показывает интерес к продукту:
- зарегистрировался;
- записался на демо;
- подписался на рассылку.
Событие лида задаёт личность клиента и ссылку, по которой он пришёл: все его дальнейшие действия (покупка, апгрейд тарифа) атрибутируются той же ссылке.
В этом руководстве мы сосредоточимся на отслеживании регистраций новых пользователей для SaaS-приложения, использующего Appwrite для аутентификации.
Что нужно до начала
Сначала включите отслеживание конверсий для ссылок: без него клик не связывается с последующими событиями лида и продажи.
Для ссылок партнёрской программы шаг можно пропустить — RevRoute включает отслеживание конверсий у них автоматически.
Для всего воркспейса. Откройте Настройки → Аналитика и включите переключатель Отслеживание конверсий в шапке страницы — он управляет настройкой на уровне воркспейса. Отслеживание включится у всех ссылок, созданных после этого.
Для отдельной ссылки. Откройте
конструктор ссылки и
включите переключатель Отслеживание конверсий — внутри конструктора он же
дёргается горячей клавишей C.
Через API. Передайте trackConversion: true при создании или обновлении
ссылки (по умолчанию — false):
curl -X POST "https://api.revroute.ru/links" \
-H "Authorization: Bearer dub_xxxxxx" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com",
"trackConversion": true
}'Затем установите на сайт клиентский скрипт RevRoute — он фиксирует клик и сохраняет его идентификатор, без которого события лида не к чему привязать.
Клиентский скрипт RevRoute отдаётся с нашего домена — npm-пакеты ставить не
нужно. Скрипт находит в URL параметр rr_id, сохраняет его в first-party cookie
rr_id на вашем домене (90 дней) и по нему связывает будущие конверсии с
исходной ссылкой.
Вставьте тег в секцию <head> каждой страницы сайта:
<script defer src="https://app.revroute.ru/analytics/script.js"></script>В Next.js (App Router) — через next/script в корневом layout:
import Script from "next/script";
export default function RootLayout({ children }) {
return (
<html lang="ru">
<body>{children}</body>
<Script defer src="https://app.revroute.ru/analytics/script.js" />
</html>
);
}Варианты скрипта (site visit, outbound domains, клиентские конверсии) и все
его атрибуты data-* описаны в разделе Варианты
скрипта.
Проверить установку можно двумя способами:
- Откройте консоль браузера и введите
_revRouteAnalytics— если скрипт установлен, в консоли появится объект. - Добавьте к адресу сайта параметр
?rr_id=testи убедитесь, что в браузере появился cookierr_id.
Если оба пункта не сработали, проверьте, что:
- тег скрипта стоит в секции
<head>страницы; - кеш CDN сброшен, если сайт отдаётся через CDN.
Серверный клиент RevRoute
Примеры ниже используют официальный TypeScript-SDK. Он ставится из npm под
именем dub — форк RevRoute отдельного пакета не публикует, поэтому в SDK
обязательно указывается наш serverURL, иначе запросы уйдут в api.dub.co.
npm install dubimport { Dub } from "dub";
export const dub = new Dub({
token: process.env.REVROUTE_API_KEY, // секретный ключ dub_* из настроек воркспейса
serverURL: "https://api.revroute.ru", // без него SDK пойдёт в api.dub.co
});Секретный ключ (dub_*) держите в переменных окружения и не отдавайте в
браузер. Ключ создаётся в разделе API-ключей .
SDK не обязателен: /track/lead и /track/sale — обычные HTTPS-эндпоинты,
их можно вызвать из любого языка (см. Track
lead).
Настройка Appwrite
Далее настройте Appwrite для отслеживания событий конверсий лидов в процессе регистрации.
Создайте проект в Appwrite Cloud
Зайдите в Appwrite Cloud и создайте новый проект.

Создайте API-ключ со скоупом sessions.write и сохраните его — он понадобится дальше. Идентификатор проекта и адрес эндпоинта можно скопировать на странице Settings проекта.

Затем установите Appwrite Node.js SDK в вашем приложении на Next.js.
npm i node-appwriteДобавьте переменные окружения
Добавьте в приложение следующие переменные окружения.
NEXT_PUBLIC_APPWRITE_ENDPOINT=https://cloud.appwrite.io/v1
NEXT_PUBLIC_APPWRITE_PROJECT=<APPWRITE_PROJECT_ID>
NEXT_APPWRITE_KEY=<APPWRITE_API_KEY>
NEXT_REVROUTE_API_KEY=<REVROUTE_API_KEY>Подключите Revroute Analytics
Добавьте клиентский скрипт RevRoute в корневой layout приложения — npm-пакет не нужен, скрипт отдаётся с нашего домена.
import type { Metadata } from 'next';
export const metadata: Metadata = {
title: 'Appwrite Revroute Leads Example',
description: 'Appwrite Revroute Leads Tracking example app with Next.js'
};
export default function RootLayout({
children
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en">
<body>{children}</body>
<script
defer
src="https://app.revroute.ru/analytics/script.js"
data-api-host="https://api.revroute.ru"
/>
</html>
);
}Подготовьте клиент Appwrite и библиотеку аутентификации
Создайте Session- и Admin-клиенты Appwrite — они нужны приложениям с серверным рендерингом, см. документацию Appwrite . Заодно напишите функцию проверки входа пользователя.
'use server';
import { Client, Account } from 'node-appwrite';
import { cookies } from 'next/headers';
export async function createSessionClient() {
const client = new Client()
.setEndpoint(process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT as string)
.setProject(process.env.NEXT_PUBLIC_APPWRITE_PROJECT as string);
const session = (await cookies()).get('my-custom-session');
if (!session || !session.value) {
throw new Error('No session');
}
client.setSession(session.value);
return {
get account() {
return new Account(client);
}
};
}
export async function createAdminClient() {
const client = new Client()
.setEndpoint(process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT as string)
.setProject(process.env.NEXT_PUBLIC_APPWRITE_PROJECT as string)
.setKey(process.env.NEXT_APPWRITE_KEY as string);
return {
get account() {
return new Account(client);
}
};
}Настройте SDK Revroute
Создайте клиент Revroute и отправляйте лиды функцией dub.track.lead().
import type { Models } from 'node-appwrite';
import { Revroute } from 'dub';
const dub = new Revroute({
token: process.env.NEXT_REVROUTE_API_KEY
});
export function addDubLead(user: Models.User<Models.Preferences>, rr_id: string) {
dub.track.lead({
clickId: rr_id,
eventName: 'Sign Up',
customerExternalId: user.$id,
customerName: user.name,
customerEmail: user.email
});
}Отправляйте лид при регистрации пользователя
На странице /auth регистрируйте пользователей через Admin-клиент Appwrite. После регистрации проверьте, есть ли cookie rr_id: если есть — отправьте событие лида в Revroute и удалите cookie.
import { ID } from 'node-appwrite';
import { createAdminClient, getLoggedInUser } from '@/lib/server/appwrite';
import { cookies } from 'next/headers';
import { redirect } from 'next/navigation';
import { addDubLead } from '@/lib/server/dub';
async function signUpWithEmail(formData: any) {
'use server';
// Get sign up info from form
const email = formData.get('email');
const password = formData.get('password');
const name = formData.get('name');
// Create account and session using Appwrite
const { account } = await createAdminClient();
const user = await account.create(ID.unique(), email, password, name);
const session = await account.createEmailPasswordSession(email, password);
(await cookies()).set('my-custom-session', session.secret, {
path: '/',
httpOnly: true,
sameSite: 'strict',
secure: true
});
// Check if Revroute ID is present in cookies and track lead if found
const rr_id = (await cookies()).get('rr_id')?.value;
if (rr_id) {
addDubLead(user, rr_id);
(await cookies()).delete('rr_id');
}
// Redirect to success page
redirect('/auth/success');
}
export default async function SignUpPage() {
// Verify active user session and redirect to success page if found
const user = await getLoggedInUser();
if (user) redirect('/auth/success');
return (
<>
<form action={signUpWithEmail}>
<input id="email" name="email" placeholder="Email" type="email" required />
<input id="password" name="password" placeholder="Password" minLength={8} type="password" required />
<input id="name" name="name" placeholder="Name" type="text" required />
<button type="submit">Sign up</button>
</form>
</>
);
}Поля запроса POST /track/lead:
| Поле | Обяз. | Описание |
|---|---|---|
clickId | да | Идентификатор клика, к которому привязывается лид. Читается из cookie rr_id. Для отложенного лида допустима пустая строка — тогда клик берётся у клиента, найденного по customerExternalId. |
eventName | да | Название события (например, Sign up). Оно же связывает лид с последующей продажей через leadEventName в /track/sale. |
customerExternalId | да | Идентификатор клиента в вашей системе. По нему атрибутируются все будущие события этого клиента. |
discountCode | нет | Промокод партнёра, если клиент пришёл без клика по ссылке. Если переданы и clickId, и discountCode, приоритет у clickId. |
customerName | нет | Имя клиента. Если не передать, сгенерируется случайное. |
customerEmail | нет | Email клиента. |
customerAvatar | нет | URL аватара клиента. |
mode | нет | async (по умолчанию) — не блокировать запрос; wait — дождаться записи события; deferred — отложить создание лида до следующего запроса. |
eventQuantity | нет | Числовое значение события (например, количество мест в триале): лид будет засчитан столько раз. |
metadata | нет | Произвольные данные события, до 10 000 символов в JSON. |
Пример приложения
Чтобы узнать больше об отслеживании лидов с Appwrite, ознакомьтесь со следующим примером приложения:
Appwrite + Revroute: пример на Next.js
Пример отслеживания регистраций через Appwrite и SDK Revroute.
Где смотреть конверсии
После настройки все отслеженные конверсии видны в аналитике воркспейса — в трёх представлениях:
- График по времени — клики, лиды и продажи в динамике: Аналитика .
- Воронка — конверсия и отвал на каждом шаге (клики → лиды → продажи): Аналитика в режиме воронки .
- Поток событий — каждое событие конверсии по всем ссылкам воркспейса в реальном времени: События .