مستندات فنی

راهنمای نصب و API آلفانا

نصب SDK، پیکربندی، React Hooks، Tracker API، فیچر فلگ، A/B تست و راهنمای رشد و رفتار — به ترتیب فهرست کنار صفحه.

معرفی

آلفانا یک SDK رهگیری رفتار برای React، Next.js، Vanilla JS و وردپرس است. ناوبری SPA، زمان حضور، heatmap (با فیلتر مسیر اختیاری)، لاگ‌های زمان اجرا، ضربان نشست، فیچر فلگ، A/B تست و سیگنال‌هایی مثل rage click و U-turn — بدون اسکریپت شخص ثالث.

پکیج npm: alphana-sdkورودی‌ها alphana-sdk و alphana-sdk/react.

نقشه حرارتی

کلیک، موس و اسکرول با نمونه‌برداری؛ burst کلیک (rage) برای نقاط گیر.

زمان حضور

جمع زمان به میلی‌ثانیه به ازای هر مسیر.

ناوبری SPA

pushState / replaceState / popstate و تشخیص ترک سریع صفحه (U-turn).

فیچر فلگ

ارزیابی سمت سرور با هدف‌گیری روی ویژگی‌های کاربر پس از identify().

لاگ و خطا

console و خطاهای سراسری با ارسال به /logs/ingest.

حریم خصوصی

بدون کوکی تحلیلگر شخص ثالث؛ شناسه بازدیدکننده در مرورگر.

نصب

آخرین نسخه روی npm (alphana-sdk) منتشر می‌شود. با هر package manager نصب کنید:

bash
# npm
npm install alphana-sdk

# pnpm
pnpm add alphana-sdk

# yarn
yarn add alphana-sdk

# bun
bun add alphana-sdk

نصب با Script / Google Tag Manager

اگر نمی‌خواهید پکیج npm نصب کنید، نسخه CDN را با یک تگ script در head یا GTM Custom HTML قرار دهید. SDK از روی data-app-id و data-secret-key خودش را مقداردهی و شروع می‌کند.

html
<script
  async
  src="https://storage.alphana.ir/cdn/alphana-sdk/latest/alphana-sdk.js"
  data-app-id="YOUR_APP_ID"
  data-secret-key="YOUR_SECRET_KEY"
></script>

برای GTM یک Custom HTML Tag بسازید، همین کد را قرار دهید و Trigger را روی All Pages بگذارید.

امنیت نصب مرورگر: درخواست‌های SDK با Bearer token، appId و دامنه ثبت‌شده اپ اعتبارسنجی می‌شوند. اگر کسی همین snippet را در سایت دیگری اجرا کند، Origin/Referer آن دامنه با دامنه اپ شما match نمی‌شود و backend درخواست را رد می‌کند.

React / Vite

UserTrackerProvider را یک بار دور کل اپ بپیچید، معمولاً در main.tsx.

tsx
// main.tsx
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import { UserTrackerProvider } from 'alphana-sdk/react';
import App from './App';

createRoot(document.getElementById('root')!).render(
  <StrictMode>
    <UserTrackerProvider
      config={{
        appId: import.meta.env.VITE_TRACKER_APP_ID,
        secretKey: import.meta.env.VITE_TRACKER_SECRET,
      }}
    >
      <App />
    </UserTrackerProvider>
  </StrictMode>
);
bash
# .env.local
VITE_TRACKER_APP_ID=your_app_id_here
VITE_TRACKER_SECRET=your_secret_key_here

Next.js App Router

چون UserTrackerProvider از hooks استفاده می‌کند، باید در یک Client Component باشد.

گام ۱ — ساخت Providers component

tsx
// app/providers.tsx
'use client';
import { UserTrackerProvider } from 'alphana-sdk/react';
import type { ReactNode } from 'react';

export function Providers({ children }: { children: ReactNode }) {
  return (
    <UserTrackerProvider
      config={{
        appId: process.env.NEXT_PUBLIC_TRACKER_APP_ID!,
        secretKey: process.env.NEXT_PUBLIC_TRACKER_SECRET!,
      }}
    >
      {children}
    </UserTrackerProvider>
  );
}

گام ۲ — استفاده در layout.tsx

tsx
// app/layout.tsx
import { Providers } from './providers';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="fa" dir="rtl">
      <body>
        <Providers>{children}</Providers>
      </body>
    </html>
  );
}

گام ۳ — متغیرهای محیطی

bash
# .env.local
NEXT_PUBLIC_TRACKER_APP_ID=your_app_id_here
NEXT_PUBLIC_TRACKER_SECRET=your_secret_key_here

گام ۴ — ردیابی مسیر در App Router

برای ثبت هر تغییر مسیر، usePageView(usePathname()) را در یک Client Component صدا بزنید (مثلاً داخل همان Providers یا layout).

tsx
// app/navigation-tracker.tsx
'use client';
import { usePathname } from 'next/navigation';
import { usePageView } from 'alphana-sdk/react';

export function NavigationTracker() {
  usePageView(usePathname());
  return null;
}
tsx
// در layout یا providers، بعد از UserTrackerProvider:
import { NavigationTracker } from './navigation-tracker';
// ...
<Providers>
  <NavigationTracker />
  {children}
</Providers>

Vanilla JS / TS

بدون هیچ فریم‌وری — فقط یک instance از UserTracker بسازید و init() صدا بزنید.

ts
import { UserTracker } from 'alphana-sdk';

const tracker = new UserTracker({
  appId: 'YOUR_APP_ID',
  secretKey: 'YOUR_SECRET_KEY',
});

// یک بار در شروع برنامه فراخوانی کنید
tracker.init();

// هنگام logout یا unmount
tracker.destroy();

وردپرس

برای سایت‌های وردپرس از افزونه Alphana Tracker استفاده کنید — بدون npm، فقط فایل ZIP و پنل مدیریت.

مراحل نصب

  1. در پیشخوان وردپرس: افزونه‌ها → افزودن → بارگذاری افزونه و فایل ZIP را انتخاب کنید؛ یا محتوای ZIP را در wp-content/plugins/alphana-tracker/ قرار دهید.
  2. افزونه را فعال کنید.
  3. به تنظیمات → Alphana Tracker بروید، App ID و Secret Key را از داشبورد آلفانا وارد کنید.
  4. گزینه فعال‌سازی رهگیری را علامت بزنید و ذخیره کنید. اسکریپت روی تمام صفحات عمومی سایت تزریق می‌شود.
  5. برای ثبت هدف یا درآمد بدون کدنویسی، به دکمه/لینک در صفحه یک id بدهید؛ سپس همان شناسه را در داشبورد در صفحه Goals یا Revenue با تریگر «کلیک روی المنت» تنظیم کنید.
html
<button id="signup-btn">ثبت‌نام</button>
<button id="checkout-btn" data-alphana-amount="1490000" data-alphana-currency="IRR">
  خرید
</button>

تنظیمات کامل

تمام گزینه‌های قابل پاس دادن به TrackerConfig:

نامنوعتوضیح
appIdاجباریstringشناسه اپ از داشبورد آلفانا؛ برای کلود اجباری است.
secretKeyاجباریstringکلید SDK برای Bearer token. در مرورگر با appId و دامنه ثبت‌شده اعتبارسنجی می‌شود.
endpointstringآدرس رویدادها؛ پیش‌فرض https://api.alphana.ir/api/events. ارسال دسته‌ای: …/batch، ضربان: …/heartbeat.
sessionIdstringشناسه نشست ثابت؛ در غیر این صورت UUID خودکار.
trackNavigationbooleanردیابی pushState/replaceState/popstate و U-turn. پیش‌فرض: true
trackHeatmapbooleanheatmap + rage click. پیش‌فرض: true
trackTimebooleanزمان تجمعی به ازای هر مسیر. پیش‌فرض: true
heatmapPagesstring[]منسوخ — ثبت صفحات فقط از پنل Heatmap Pages انجام می‌شود. سرور خودش مسیرهای مجاز را فیلتر می‌کند.
trackLogsbooleanconsole.info/warn/error، onerror، unhandledrejection → /logs/ingest. پیش‌فرض: true
mouseSampleRatenumber (0–1)درصد نمونه‌برداری رویداد موس/اسکرول. پیش‌فرض: 0.3
maxHeatmapPointsnumberحداکثر نقاط heatmap در حافظه به ازای هر مسیر. پیش‌فرض: 2000
batchSizenumberاندازه صف قبل از flush خودکار. پیش‌فرض: 20
flushIntervalnumber (ms)فاصله flush خودکار. پیش‌فرض: 5000
onEvent(event) => voidcallback هم‌زمان برای هر رویداد emit‌شده.
consentMode"auto" | "disabled"auto (پیش‌فرض): اگر ویجت رضایت کوکی در داشبورد فعال باشد، تا پذیرش کاربر ردیابی شروع نمی‌شود. disabled: بنر نشان داده نمی‌شود و ردیابی فوری است.

از SDK نسخه 2.0.5، می‌توانید ویجت‌های داخل‌سایت را از داشبورد → Widgets فعال کنید. ابتدا رضایت کوکی: محتوا و تم قابل سفارشی‌سازی است. اگر فعال باشد:

  • تا پذیرش کاربر، هیچ ردیابی‌ای (pageview، heatmap، replay، goal، revenue، لاگ) انجام نمی‌شود.
  • در صورت رد، ردیابی برای آن بازدیدکننده خاموش می‌ماند.
  • انتخاب در مرورگر ذخیره می‌شود؛ با افزایش version در تنظیمات ویجت، بنر دوباره نمایش داده می‌شود.
  • اگر ویجت غیرفعال باشد، رفتار قبلی حفظ می‌شود و ردیابی فوری شروع می‌شود.
ts
new UserTracker({
  appId: 'YOUR_APP_ID',
  secretKey: 'YOUR_SECRET_KEY',
  // اختیاری: بنر را در کلاینت نادیده بگیرید حتی اگر در داشبورد فعال باشد
  consentMode: 'auto', // یا 'disabled'
}).init();

ویجت بازخورد

ویجت بازخورد امتیاز ۱ تا ۵ به‌همراه نظر اختیاری را جمع‌آوری می‌کند. از داشبورد → Widgets → Feedback فعال کنید.

  • پس از delaySeconds به‌صورت خودکار نمایش داده می‌شود.
  • برای هر version فقط یک‌بار (ارسال یا بستن) در localStorage ذخیره می‌شود.
  • برخلاف رضایت کوکی، این ویجت ردیابی را مسدود نمی‌کند.
  • پاسخ‌ها در داشبورد → Widgets → Responses قابل مشاهده‌اند.

ویجت نظرسنجی

ویجت نظرسنجی سؤالات مرتب‌شده از نوع متن، امتیاز، تک‌انتخابی و چندانتخابی را نمایش می‌دهد. از داشبورد → Widgets → Survey پیکربندی کنید.

  • همان قوانین تأخیر (delaySeconds) و یک‌بار در هر version اعمال می‌شود.
  • ردیابی را مسدود نمی‌کند.
  • پاسخ‌ها از طریق POST /api/sdk/widget-responses ذخیره می‌شوند و در داشبورد لیست می‌شوند.

ساخت API Key

API Key آلفانا برای اتصال سرور به سرور به Public Analytics API است. این کلید با Secret Key هر اپ که SDK برای ثبت رویداد استفاده می‌کند تفاوت دارد و نباید در JavaScript مرورگر، اپ موبایل یا مخزن عمومی قرار بگیرد.

کلید سطح حساب

به اپ‌های متعلق به حساب و اپ‌های share‌شده با همان کاربر دسترسی دارد.

نمایش فقط یک‌بار

مقدار کامل کلید فقط هنگام ساخت یا rotate نمایش داده می‌شود؛ آلفانا آن را بازیابی نمی‌کند.

Rotate امن

با rotate، کلید قبلی بلافاصله نامعتبر و یک کلید جدید صادر می‌شود.

مراحل تولید کلید

  1. وارد داشبورد آلفانا شوید و از منوی حساب به API Keys بروید.
  2. روی ساخت API Key کلیک کنید. هر حساب در حال حاضر یک API Key فعال دارد.
  3. مقدار با پیشوند alphana_api_ را همان لحظه کپی و در Secret Manager یا متغیر محیطی سمت سرور ذخیره کنید.
  4. اگر کلید افشا شد، از همان صفحه گزینه Rotate را بزنید و مقدار جدید را در سرویس‌های مصرف‌کننده جایگزین کنید.
bash
# .env — فقط سمت سرور
ALPHANA_API_KEY=alphana_api_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
تفاوت دو credential: alphana_api_… برای خواندن Public API و مدیریت اپ‌ها در backend شماست. SDK Secret هر اپ برای ingestion داده همان اپ است؛ این دو قابل جایگزینی نیستند.

احراز هویت Public API

Base URL برابر https://api.alphana.ir است. در همه درخواست‌ها API Key را در هدر Bearer بفرستید. برای پیدا کردن appId ابتدا لیست اپ‌ها را دریافت کنید.

bash
curl --request GET \
  --url https://api.alphana.ir/api/v1/apps \
  --header "Authorization: Bearer $ALPHANA_API_KEY" \
  --header "Accept: application/json"
json
[
  {
    "id": "11111111-1111-4111-8111-111111111111",
    "name": "Storefront",
    "domain": "https://example.com",
    "active": true,
    "createdAt": "2026-07-01T10:00:00.000Z",
    "updatedAt": "2026-07-20T09:15:00.000Z"
  }
]

بازه زمانی

endpointهای تحلیلی به appIdنیاز دارند. پارامترهای اختیاری from و to باید ISO 8601 باشند؛ مقدار date-only از ساعت ۰۰:۰۰ UTC محاسبه می‌شود.

bash
curl --get \
  --url https://api.alphana.ir/api/v1/sessions/overview/kpis \
  --header "Authorization: Bearer $ALPHANA_API_KEY" \
  --data-urlencode "appId=11111111-1111-4111-8111-111111111111" \
  --data-urlencode "from=2026-07-14T00:00:00.000Z" \
  --data-urlencode "to=2026-07-21T23:59:59.999Z"

Rate limit و خطاها

مقدار پیش‌فرض ۱۲۰ درخواست در دقیقه برای هر API Key است. وضعیت مصرف در هدرهای X-RateLimit-Limit، X-RateLimit-Remaining و X-RateLimit-Reset برمی‌گردد. پاسخ ۴۲۹ علاوه بر Retry-After، فیلد retryAfterSeconds دارد.

Endpointها و خروجی‌ها

Public API نسخه ۱ شامل عملیات Apps، Sessions و Growth است. تمام endpointهای زیر JSON برمی‌گردانند و به Bearer API Key نیاز دارند.

متد و مسیرورودیخروجی
GET/api/v1/appsآرایه اپ‌های قابل دسترس: id، name، domain، active، createdAt و updatedAt.
POST/api/v1/appsBody: name و domainاپ ساخته‌شده به‌همراه _id، مشخصات اپ و SDK ingestion secret یک‌باره.
GET/api/v1/sessions/data-boundsappIdfirstDataAt و lastDataAt؛ اگر داده‌ای نباشد هر دو null هستند.
GET/api/v1/sessions/overview/extendedappId، from؟، to؟KPI نشست، دکمه‌ها و صفحات برتر، rage click، U-turn، صفحات مسئله‌دار، فناوری‌ها، کشورها، خطاها و منابع ترافیک.
GET/api/v1/sessions/overview/kpisappId، from؟، to؟current، previous و changePct برای visitors، views، visits، bounceRate و visitDurationMs.
GET/api/v1/sessions/pageviewsappId، from؟، to؟آرایه path، views و uniqueVisitors مرتب‌شده بر اساس بازدید.
GET/api/v1/sessions/timespentappId، from؟، to؟آرایه path، totalMs، avgMs و sessions.
GET/api/v1/sessions/user-growthappId، from؟، to؟روند روزانه date، sessions، users، views و clicks بر مبنای UTC.
GET/api/v1/sessions/traffic-heatmapappIdهفت روز اخیر تهران: days با ۲۴ مقدار ساعتی و maxCount برای مقیاس نمودار.
GET/api/v1/sessions/traffic-audience-activityappIdمیانگین فعالیت ۲۸ روزه در byWeekday و byHour همراه lookbackDays.
GET/api/v1/sessions/locations/allappId، from؟، to؟آرایه country، countryName، city، latitude، longitude و count.
GET/api/v1/growth/utmappId، from؟، to؟حداکثر ۱۰۰ ترکیب source، medium، campaign، term، content با sessions و visitors.

نمونه خروجی KPI

json
{
  "period": "lastWeek",
  "compareEnabled": true,
  "current": {
    "visitors": 1240,
    "views": 3980,
    "visits": 1520,
    "bounceRate": 41.7,
    "visitDurationMs": 86342.5
  },
  "previous": {
    "visitors": 1103,
    "views": 3682,
    "visits": 1374,
    "bounceRate": 43.1,
    "visitDurationMs": 81687.3
  },
  "changePct": {
    "visitors": 12.4,
    "views": 8.1,
    "visits": 10.6,
    "bounceRate": -3.2,
    "visitDurationMs": 5.7
  }
}

ساخت اپ از API

bash
curl --request POST \
  --url https://api.alphana.ir/api/v1/apps \
  --header "Authorization: Bearer $ALPHANA_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{"name":"Storefront","domain":"https://example.com"}'
مهم: پاسخ ساخت اپ شامل SDK ingestion secret است. آن را امن ذخیره کنید و در لاگ یا پاسخ عمومی سرور نمایش ندهید. endpoint لیست اپ‌ها عمداً این secret را برنمی‌گرداند.

React Hooks

وقتی از alphana-sdk/react استفاده می‌کنید این hooks در دسترس هستند:

Hookخروجیتوضیح
useTracker()UserTracker | nullinstance tracker از context؛ بیرون از Provider برابر null است.
usePageView(path?)voidبا تغییر path، trackPageView را صدا می‌زند؛ بدون path کاری نمی‌کند (مثلاً فقط برای App Router).
usePageViews()PageView[]تمام pageview های session جاری.
useHeatmapData(path?, refreshMs?)HeatmapPoint[]نقاط heatmap برای مسیر؛ به‌روزرسانی با debounce (پیش‌فرض ۵۰۰ms).
useTimeSpent()Record<string, number>زمان تجمعی به میلی‌ثانیه به ازای هر مسیر.
useTrackRevenue()(payload) => voidتابع آماده برای ارسال purchase، subscription، renewal، upgrade یا refund از داخل React.
useTrackGoal()(payload) => voidتابع آماده برای ثبت هدف‌های تبدیل مثل signup_completed یا demo_requested.
useTrackJourneyStep()(payload) => voidتابع آماده برای ثبت milestoneهای محصول مثل onboarding_done یا plan_selected.
useFeatureFlags()Record<string, boolean>تمام فلگ‌های ارزیابی‌شده برای کاربر جاری. با هر بار identify() به‌روز می‌شود.
useFeatureFlagEnabled(key)booleantrue اگر فلگ مشخص‌شده برای کاربر جاری فعال باشد، در غیر این‌صورت false.

مثال

tsx
import { useTracker, useTimeSpent, useHeatmapData } from 'alphana-sdk/react';

export function DebugPanel() {
  const tracker = useTracker();
  const timeByPath = useTimeSpent(); // Record<path, ms>
  const points = useHeatmapData();

  if (!tracker) return null;

  return (
    <div>
      <p>مسیرهای با زمان ثبت‌شده: {Object.keys(timeByPath).length}</p>
      <p>نقاط heatmap (این صفحه): {points.length}</p>
      <button type="button" onClick={() => tracker.flush()}>ارسال فوری</button>
    </div>
  );
}

Tracker API

متدهای عمومی روی instance UserTracker:

متدتوضیح
init()شروع ردیابی. ممکن است ابتدا runtime-config و رضایت کوکی را بررسی کند؛ در SSR no-op است. مقدار this را برمی‌گرداند.
destroy()توقف listenerها و تایمرها؛ ارسال بهترین تلاش برای صف باقی‌مانده.
flush()ارسال فوری صف رویدادها به /batch (بدون await).
trackPageView(path?)ثبت دستی pageview برای مسیر داده‌شده یا مسیر جاری.
identify(props)ادغام ویژگی‌های کاربر برای هدف‌گیری فلگ؛ دوباره fetchFlags.
trackRevenue(payload)ثبت خرید، اشتراک، تمدید، ارتقا یا refund همراه با attribution فعلی.
trackGoal(payload)ثبت هدف تبدیل مثل signup_completed، lead یا trial_started.
trackJourneyStep(payload)ثبت milestone سفارشی در مسیر کاربر مثل onboarding_done.
getFlags() / isFeatureEnabled(key)خواندن فلگ‌های ارزیابی‌شده.
onFlagsChange(fn) / fetchFlags()اشتراک در تغییر فلگ یا درخواست مجدد ارزیابی.
subscribe(fn)subscriber رویداد؛ تابع unsubscribe برمی‌گرداند.
getSession()snapshot نشست (شامل visitorId).
getPageViews()تمام pageviewهای نشست جاری.
getTimeSpent()Record مسیر → میلی‌ثانیه تجمعی.
getHeatmapData(path?)با path: آرایه نقاط؛ بدون آرگومان: Record همه مسیرها.
ts
import { UserTracker } from 'alphana-sdk';

const tracker = new UserTracker({ appId: 'id', secretKey: 'key' });

const unsubscribe = tracker.subscribe((event) => {
  console.log(event.type, event);
});

tracker.init();

tracker.flush(); // اختیاری — خالی کردن صف

// unsubscribe();

فیچر فلگ — معرفی

فیچر فلگ (Feature Flag) به شما امکان می‌دهد بدون دیپلوی مجدد، قابلیت‌های مختلف را برای کاربران مختلف فعال یا غیرفعال کنید. SDK آلفانا این قابلیت را به صورت built-in ارائه می‌دهد.

بدون دیپلوی

فلگ را از داشبورد تغییر دهید — تغییر بلافاصله برای کاربران اعمال می‌شود.

هدف‌گیری دقیق

فلگ را بر اساس email، plan، country یا هر property دیگری هدف‌گیری کنید.

real-time

بعد از identify() فلگ‌ها بلافاصله دوباره ارزیابی می‌شوند.

kill switch

یک قابلیت مشکل‌دار را فوری غیرفعال کنید بدون نیاز به rollback.

پلن موردنیاز: فیچر فلگ فقط در پلن‌های حرفه‌ای، اقتصادی و ویژه در دسترس است.

ساخت فلگ در داشبورد

در داشبورد به بخش فیچر فلگ‌ها بروید و روی فلگ جدید کلیک کنید.

فیلدتوضیح
keyشناسه ماشینی فلگ — فقط حروف کوچک انگلیسی، اعداد، خط‌تیره یا زیرخط. مثال: new-checkout
descriptionتوضیح اختیاری برای یادآوری هدف فلگ.
فعال/غیرفعالوضعیت کلی فلگ. اگر غیرفعال باشد برای هیچ کاربری true نمی‌شود.
شرط‌های هدف‌گیریاختیاری. اگر تعریف شود، همه شرط‌ها باید برقرار باشند (AND). بدون شرط یعنی برای همه فعال است.

استفاده در SDK

React Hooks

ساده‌ترین روش — از hooks اختصاصی استفاده کنید:

tsx
import {
  useFeatureFlagEnabled,
  useFeatureFlags,
} from 'alphana-sdk/react';

// بررسی یک فلگ خاص
function CheckoutButton() {
  const showNewCheckout = useFeatureFlagEnabled('new-checkout');

  if (showNewCheckout) {
    return <NewCheckout />;
  }
  return <OldCheckout />;
}

// دریافت همه فلگ‌ها
function DebugFlags() {
  const flags = useFeatureFlags();
  // { 'new-checkout': true, 'promo-banner': false, ... }
  return <pre>{JSON.stringify(flags, null, 2)}</pre>;
}

شناسایی کاربر

برای استفاده از شرط‌های هدف‌گیری (مثل email یا plan)، ابتدا کاربر را شناسایی کنید:

tsx
import { useTracker } from 'alphana-sdk/react';

function AuthWrapper({ user }) {
  const tracker = useTracker();

  useEffect(() => {
    if (user && tracker) {
      // properties به عنوان شرط‌های هدف‌گیری استفاده می‌شوند
      tracker.identify({
        email: user.email,
        plan: user.plan,       // 'trial' | 'pro' | ...
        country: user.country, // 'IR' | 'US' | ...
      });
    }
  }, [user, tracker]);

  return <>{children}</>;
}

Vanilla JS

ts
const tracker = new UserTracker({
  appId: 'YOUR_APP_ID',
  secretKey: 'YOUR_SECRET_KEY',
}).init();

// شناسایی کاربر
tracker.identify({ email: 'user@example.com', plan: 'pro' });

// بررسی فلگ
if (tracker.isFeatureEnabled('new-checkout')) {
  showNewCheckout();
}

// گوش دادن به تغییرات فلگ
const unsub = tracker.onFlagsChange((flags) => {
  console.log('flags updated:', flags);
});

// دریافت همه فلگ‌ها
const allFlags = tracker.getFlags();
// { 'new-checkout': true, 'promo-banner': false }

شرط‌های هدف‌گیری

هر فلگ می‌تواند یک یا چند شرط داشته باشد. تمام شرط‌ها باید برقرار باشند (AND). اگر شرطی تعریف نشود، فلگ برای همه فعال است.

operatorتوضیحمثال
equalsمقدار دقیقاً برابر باشد (case-insensitive)email equals user@example.com
containsمقدار شامل رشته مشخص‌شده باشدemail contains @mycompany.com
is_inمقدار در لیست جداشده با کاما باشدplan is_in pro,economy,special
نکته: شرط‌ها روی userProperties که از طریق tracker.identify({...}) ارسال می‌کنید ارزیابی می‌شوند. اگر identify() فراخوانی نشده باشد، تمام شرط‌ها به عنوان عدم تطابق در نظر گرفته می‌شوند.

A/B تست — معرفی

A/B تست به شما امکان می‌دهد چند نسخه از UI یا جریان کاربر (واریانت) را هم‌زمان اجرا کنید و نرخ تبدیل هر نسخه را با یک هدف تبدیل (Goal) مقایسه کنید. تخصیص واریانت از طریق API انجام می‌شود؛ رهگیری رفتار و محاسبه تبدیل با همان SDK آلفانا (pageview و کلیک) انجام می‌گیرد.

تخصیص پایدار

هر visitorId همیشه همان واریانت را می‌گیرد (hash قطعی).

وزن ترافیک

مثلاً ۵۰٪ کنترل و ۵۰٪ واریانت B — مجموع وزن‌ها باید ۱۰۰ باشد.

هدف تبدیل

بازدید صفحه یا کلیک روی المنت — مثل قیف تبدیل.

گزارش در داشبورد

شرکت‌کننده، تبدیل، نرخ و Uplift نسبت به واریانت کنترل.

جریان کار: (۱) آزمایش را در داشبورد بسازید و وضعیت را running کنید — (۲) SDK را با secretKey نصب و init() کنید — (۳) با useAbVariant / tracker.getAbVariant() UI را عوض کنید — (۴) رویدادهای کاربر برای محاسبه Goal ثبت می‌شوند.

Endpoint ارزیابی

http
POST https://api.alphana.ir/api/ab-tests/evaluate
Authorization: Bearer <APP_SECRET_KEY>
Origin: https://your-registered-domain.com
Content-Type: application/json

اگر endpoint ترکر را https://api.alphana.ir/api/events گذاشته‌اید، آدرس evaluate برابر است با: https://api.alphana.ir/api/ab-tests/evaluate

در مرورگر، backend علاوه بر Bearer token، دامنه Origin / Referer را با دامنه ثبت‌شده اپ تطبیق می‌دهد.

ساخت آزمایش در داشبورد

در داشبورد به A/B تست بروید و آزمایش جدید را بزنید.

فیلدتوضیح
keyشناسه SDK — فقط a-z، 0-9، خط‌تیره و زیرخط. مثال: checkout-cta-test
variants۲ تا ۸ واریانت؛ هر کدام key، نام و weight (٪). مجموع weight = 100
goalرویداد تبدیل: بازدید صفحه یا کلیک
statusdraft (پیش‌نویس) | running (فعال برای SDK) | paused
conversionWindowHoursپنجره زمانی پس از اولین رویداد کاربر برای شمارش تبدیل (پیش‌فرض ۱۶۸ ساعت)
countByvisitor (یکتا) یا session
مهم: تا وقتی وضعیت running نباشد، endpoint evaluate واریانت برنمی‌گرداند. اولین واریانت در لیست به‌عنوان کنترل برای محاسبه Uplift استفاده می‌شود.

A/B تست — Vanilla JS / TS

با secretKey در کانفیگ ترکر، SDK پس از init() به‌صورت خودکار واریانت‌ها را از /ab-tests/evaluate می‌گیرد.

ts
import { UserTracker } from 'alphana-sdk';

const tracker = new UserTracker({
  appId: 'YOUR_APP_ID',
  secretKey: 'YOUR_SECRET_KEY',
  endpoint: 'https://api.alphana.ir/api/events',
}).init();

tracker.onAbTestsChange((variants) => {
  const variant = variants['checkout-cta-test'];
  const cta = document.getElementById('cta')!;
  if (variant === 'variant-b') {
    cta.className = 'btn-blue';
    cta.textContent = 'خرید الان';
  } else {
    cta.className = 'btn-green';
    cta.textContent = 'ادامه خرید';
  }
});

async function runCheckoutExperiment() {
  await tracker.fetchAbTests(['checkout-cta-test']);
  if (tracker.isAbVariant('checkout-cta-test', 'variant-b')) {
    document.getElementById('cta')!.className = 'btn-blue';
  } else {
    document.getElementById('cta')!.className = 'btn-green';
  }
}

void runCheckoutExperiment();
نکته: تخصیص بر اساس visitorId نشست ثابت می‌ماند. درخواست‌های مرورگر با secret، appId و دامنه ثبت‌شده اپ کنترل می‌شوند؛ با این حال اگر کلید را جایی عمومی paste کرده‌اید، آن را rotate کنید.

A/B تست — React / Vite

مثل Feature Flagها از hookهای آماده SDK استفاده کنید — نیازی به fetch دستی نیست.

tsx
// main.tsx — Provider مثل بخش Feature Flag
import { UserTrackerProvider } from 'alphana-sdk/react';

<UserTrackerProvider
  config={{
    appId: import.meta.env.VITE_TRACKER_APP_ID,
    secretKey: import.meta.env.VITE_TRACKER_SECRET,
    endpoint: 'https://api.alphana.ir/api/events',
  }}
>
  <App />
</UserTrackerProvider>
tsx
// components/CheckoutCta.tsx
import {
  useAbVariant,
  useIsAbVariant,
  useAbTests,
} from 'alphana-sdk/react';

export function CheckoutCta() {
  const variant = useAbVariant('checkout-cta-test');
  const isVariantB = useIsAbVariant('checkout-cta-test', 'variant-b');

  // variant === null تا زمان بارگذاری اول evaluate
  if (variant == null) {
    return <button className="btn-skeleton">...</button>;
  }

  if (isVariantB) {
    return <button className="btn-blue">خرید الان</button>;
  }
  return <button className="btn-green">ادامه خرید</button>;
}

// همه واریانت‌ها:
function DebugPanel() {
  const variants = useAbTests();
  return <pre>{JSON.stringify(variants, null, 2)}</pre>;
}
bash
# .env.local (فقط برای توسعه — secret را در کلاینت production نگذارید)
VITE_TRACKER_APP_ID=your_app_id
VITE_TRACKER_SECRET=your_secret_key_here

A/B تست — Next.js App Router

در Client Component از همان hookهای React SDK استفاده کنید.UserTrackerProvider را در layout قرار دهید.

گام ۱ — Provider در layout

tsx
// app/providers.tsx
'use client';
import { UserTrackerProvider } from 'alphana-sdk/react';

export function Providers({ children }: { children: React.ReactNode }) {
  return (
    <UserTrackerProvider
      config={{
        appId: process.env.NEXT_PUBLIC_TRACKER_APP_ID!,
        secretKey: process.env.NEXT_PUBLIC_TRACKER_SECRET!,
        endpoint: 'https://api.alphana.ir/api/events',
      }}
    >
      {children}
    </UserTrackerProvider>
  );
}

گام ۲ — Client Component

tsx
'use client';
import { useAbVariant, useIsAbVariant } from 'alphana-sdk/react';

export function CheckoutCta() {
  const variant = useAbVariant('checkout-cta-test');
  const isVariantB = useIsAbVariant('checkout-cta-test', 'variant-b');

  if (variant == null) {
    return <button className="btn-skeleton">...</button>;
  }

  if (isVariantB) {
    return <button className="btn-blue">خرید الان</button>;
  }
  return <button className="btn-green">ادامه خرید</button>;
}
bash
# .env.local
NEXT_PUBLIC_TRACKER_APP_ID=your_app_id
NEXT_PUBLIC_TRACKER_SECRET=your_secret_key
Production: نصب مستقیم مرورگر با appId، secret و دامنه ثبت‌شده guard می‌شود. اگر مدل امنیتی سخت‌گیرانه‌تری می‌خواهید، می‌توانید endpoint ترکر را به یک Route Handler داخلی که رویدادها و evaluate را پروکسی می‌کند اشاره دهید.

pageview و کلیک‌ها برای Goal از همان ترکر ثبت می‌شوند — آزمایش را در داشبورد با Goal رویداد (مثلاً click روی دکمه CTA) تعریف کنید.

هدف تبدیل (Goal)

تبدیل از روی داده‌های نشست (همان رویدادهای SDK) محاسبه می‌شود؛ نیازی به فراخوانی جداگانه «conversion» نیست. Goal باید با رفتار واقعی کاربران هم‌خوان باشد.

نوع Goalفیلدهامثال
page_viewpath + pathMatchمسیر /order/complete با contains
clickelementLabel + labelMatch (+ path اختیاری)کلیک روی دکمه با label «پرداخت»

pathMatch

مقدارمعنی
containsمسیر شامل رشته باشد
exactمسیر دقیقاً برابر
starts_withمسیر با پیشوند شروع شود
regexتطابق عبارت منظم
کیفیت داده: برای page_view از usePageView در SPA/Next استفاده کنید تا مسیرها درست ثبت شوند. برای click، label المنت (مثلاً متن دکمه یا data-attribute) باید با elementLabel در Goal هم‌خوان باشد.

Growth Analytics — معرفی

قابلیت‌های رشد آلفانا روی همان نصب SDK ساخته می‌شوند. SDK به صورت خودکار pageview، referrer، UTM و click idها را ثبت می‌کند؛ تیم شما فقط باید کاربران را با identify() شناسایی کند و رویدادهای درآمدی را با trackRevenue() ارسال کند.

UTM

تحلیل source، medium، campaign، term، content و click idها برای هر نشست.

Attribution

نگهداری first-touch و last-touch برای نسبت دادن تبدیل و درآمد به کانال‌ها.

Revenue

ثبت خرید، اشتراک، تمدید، ارتقا و refund کنار رفتار کاربر.

Segments

ساخت گروه‌های پویا از کاربران بر اساس رفتار، کمپین، کشور، پلن یا ویژگی‌ها.

Cohorts

دیدن عملکرد گروه‌های زمانی کاربران و مقایسه رشد، بازگشت یا ریزش.

اصل مهم: برای گزارش‌های دقیق، لینک‌های کمپین باید UTM استاندارد داشته باشند، کاربر بعد از ورود شناسایی شود و درآمد با transactionId یکتا ثبت شود.

UTM و Attribution

وقتی کاربر با لینک کمپین وارد سایت می‌شود، SDK پارامترهای UTM و click idها را از URL می‌خواند و به عنوان touchpoint ذخیره می‌کند. اولین touchpoint برای first-touch نگه داشته می‌شود و آخرین touchpoint برای last-touch به‌روزرسانی می‌شود.

لینک استاندارد کمپین

text
https://example.com/pricing?utm_source=google&utm_medium=cpc&utm_campaign=spring_sale&utm_content=hero_cta&utm_term=analytics

تیم مارکتینگ باید این پارامترها را در تمام لینک‌های تبلیغاتی، ایمیل‌ها، شبکه‌های اجتماعی و همکاری‌های affiliate استفاده کند:

پارامترکاربرد
utm_sourceمنبع ترافیک مثل google، instagram، newsletter
utm_mediumنوع کانال مثل cpc، organic، email، referral
utm_campaignنام کمپین یا launch
utm_termکلمه کلیدی یا audience هدف
utm_contentنسخه خلاقه، جایگاه لینک یا CTA
gclid / fbclid / ttclid / msclkidشناسه کلیک پلتفرم‌های تبلیغاتی

کاری که تیم فنی باید انجام دهد

برای UTM و Attribution، نصب معمول SDK کافی است. اگر از Next.js App Router استفاده می‌کنید، حتماً usePageView() را طبق بخش Next.js فعال کنید تا تغییر مسیرهای SPA هم ثبت شوند.

Revenue — ثبت درآمد و تبدیل

گزارش Revenue زمانی دقیق می‌شود که بعد از پرداخت موفق، تمدید، ارتقای پلن یا refund، یک رویداد درآمدی ارسال کنید. این رویداد به first-touch و last-touch کاربر وصل می‌شود تا درآمد هر کمپین مشخص شود.

Vanilla JS / TS

ts
import { UserTracker } from 'alphana-sdk';

const tracker = new UserTracker({
  appId: 'YOUR_APP_ID',
  secretKey: 'YOUR_SECRET_KEY',
}).init();

// بعد از پرداخت موفق در checkout یا callback سمت کلاینت
tracker.trackRevenue({
  eventName: 'purchase',
  transactionId: 'order_12345',
  orderId: 'order_12345',
  amount: 1490000,
  currency: 'IRR',
  productId: 'pro-plan',
  planId: 'pro',
  coupon: 'SPRING20',
  status: 'paid',
  items: [
    { id: 'pro-plan', name: 'Pro Plan', quantity: 1, price: 1490000 },
  ],
  metadata: {
    billingPeriod: 'monthly',
  },
});

React

tsx
import { useTrackRevenue } from 'alphana-sdk/react';

export function PaymentSuccess({ order }: { order: Order }) {
  const trackRevenue = useTrackRevenue();

  useEffect(() => {
    trackRevenue({
      eventName: 'subscription',
      transactionId: order.id,
      amount: order.amount,
      currency: order.currency,
      planId: order.planSlug,
      status: 'paid',
    });
  }, [order, trackRevenue]);

  return <p>پرداخت با موفقیت انجام شد.</p>;
}
نکته برای تیم بک‌اند: اگر پرداخت فقط در سرور تأیید می‌شود، transactionId و مبلغ را از سرور به صفحه success منتقل کنید یا یک endpoint امن برای ارسال رویداد revenue در سمت سرور بسازید. transactionId باید یکتا باشد تا رویداد تکراری شمرده نشود.

تریگر کلیک روی المنت (بدون کد)

در داشبورد → Revenue یک تریگر با نوع «کلیک روی المنت» بسازید، مبلغ و ارز پیش‌فرض را وارد کنید و elementId را با id دکمه سایت یکی کنید. در صورت نیاز می‌توانید مبلغ را با data-attribute روی المنت override کنید:

html
<button
  id="checkout-btn"
  data-alphana-amount="1490000"
  data-alphana-currency="IRR"
  data-alphana-event-name="purchase"
>
  تکمیل خرید
</button>

Segments و Cohorts

سگمنت‌ها و کوهورت‌ها در داشبورد از داده‌هایی ساخته می‌شوند که SDK جمع‌آوری می‌کند: نشست‌ها، UTM، کشور، دستگاه، صفحات دیده‌شده، درآمد و ویژگی‌های کاربر. برای اینکه این بخش‌ها واقعاً مفید شوند، باید بعد از login یا signup کاربر را شناسایی کنید.

شناسایی کاربر و ویژگی‌های هدف‌گیری

ts
tracker.identify({
  id: user.id,
  email: user.email,
  plan: user.plan,          // trial | pro | enterprise
  role: user.role,          // admin | member
  country: user.country,    // IR | DE | ...
  companySize: user.companySize,
});

بعد از این مرحله می‌توانید در داشبورد سگمنت‌هایی مثل «کاربران پلن pro از Google Ads»، «کاربران ایران»، «کاربران newsletter که خرید نکرده‌اند» یا «کاربران دارای revenue» بسازید.

کوهورت‌ها چطور کار می‌کنند؟

کوهورت‌ها کاربران را بر اساس زمان اولین مشاهده، signup یا purchase گروه‌بندی می‌کنند. سپس می‌توانید ببینید هر گروه در هفته‌ها یا ماه‌های بعد چه تعداد نشست، بازگشت یا درآمد ایجاد کرده است.

چک‌لیست استفاده برای تیم‌ها

تیمکار لازم
EngineeringSDK را نصب کند، appId/secretKey را تنظیم کند، identify و trackRevenue را در نقاط درست صدا بزند.
Marketingبرای همه کمپین‌ها UTM استاندارد و نام‌گذاری ثابت تعریف کند.
Productسگمنت‌ها، کوهورت‌ها و conversionهای مهم را مشخص کند.
Data / Growthمدل attribution، بازه گزارش‌گیری و تعریف revenue/refund را با تیم‌ها هماهنگ کند.
QAبا یک لینک UTM تستی وارد شود، login کند، پرداخت تستی بزند و داشبورد UTM/Revenue/Attribution را بررسی کند.
text
QA flow:
1. Open /?utm_source=qa&utm_medium=test&utm_campaign=growth_docs
2. Sign up or log in
3. Call tracker.identify({...})
4. Complete a test purchase
5. Verify Dashboard → UTM, Revenue, Attribution, Segments, Cohorts

Behavior Analytics — معرفی

بخش Behavior برای پاسخ به سه سؤال اصلی ساخته شده است: کاربران چه هدف‌هایی را کامل می‌کنند، از چه مسیرهایی عبور می‌کنند و آیا دوباره برمی‌گردند یا نه. Pageview و visitorId به صورت خودکار ثبت می‌شوند؛ تیم فنی فقط باید هدف‌ها و milestoneهای مهم را نام‌گذاری و ارسال کند.

Goals

رویدادهای تبدیل مثل signup، lead، trial_start یا activation.

Journeys

صفحات ورود، انتقال بین صفحات و milestoneهای سفارشی محصول.

Retention

بازگشت کاربران در نشست‌های بعدی بر اساس visitorId و identify.

Goals — ثبت هدف‌های تبدیل

Goal یعنی یک نتیجه مهم برای کسب‌وکار یا محصول؛ مثل ثبت‌نام کامل، ارسال فرم دمو، شروع trial، افزودن به سبد یا تکمیل onboarding. تیم محصول ابتدا goal key را در داشبورد، صفحه Goals تعریف می‌کند؛ سپس تیم فنی همان key را در SDK ارسال می‌کند.

ts
tracker.trackGoal({
  key: 'signup_completed',
  name: 'Signup completed',
  value: 1,
  metadata: {
    source: 'pricing_page',
  },
});
tsx
import { useTrackGoal } from 'alphana-sdk/react';

export function SignupSuccess() {
  const trackGoal = useTrackGoal();

  useEffect(() => {
    trackGoal({ key: 'signup_completed', name: 'Signup completed' });
  }, [trackGoal]);

  return <p>ثبت‌نام کامل شد.</p>;
}
پیشنهاد نام‌گذاری: کلید goal را ثابت، انگلیسی و snake_case نگه دارید؛ مثل demo_requested یا trial_started.

تریگر کلیک روی المنت (بدون کد)

در داشبورد → Goals تریگر را روی «کلیک روی المنت» بگذارید و شناسه HTML را وارد کنید. این بخش فقط برای هدف‌ها است؛ درآمد را از صفحه Revenue پیکربندی کنید.

html
<button id="signup-btn">ثبت‌نام</button>

Journeys — مسیر کاربران

آلفانا مسیر کاربران را از pageviewهای خودکار می‌سازد. اگر در محصول milestoneهایی دارید که الزاماً تغییر URL ندارند، آن‌ها را با trackJourneyStep() ثبت کنید.

ts
tracker.trackJourneyStep({
  key: 'plan_selected',
  label: 'Plan selected',
  metadata: {
    plan: 'pro',
  },
});

برای SPAها و Next.js App Router، طبق بخش نصب Next.js مطمئن شوید کهusePageView() روی تغییر مسیرها اجرا می‌شود؛ در غیر این صورت journey فقط اولین pageview را دارد.

Retention — بازگشت کاربران

Retention از نشست‌های تکراری یک visitor ساخته می‌شود. SDK به صورت خودکار visitorId را در مرورگر نگه می‌دارد، اما برای دقت بیشتر بین دستگاه‌ها یا بعد از login، حتماً identify() را صدا بزنید.

ts
tracker.identify({
  id: user.id,
  email: user.email,
  plan: user.plan,
});

تیم محصول باید بازه تحلیل را مشخص کند: retention روزانه برای محصول‌های پرتکرار، هفتگی برای SaaS و ماهانه برای خریدهای با فاصله بیشتر مناسب‌تر است.