Add Яндекс.Метрика funnel goals: signup_free + gate_view (env-driven counter)

- window.ym reachGoal 'signup_free' on registration success
- GateViewTracker client component fires 'gate_view' on tripwire gate mount
- counter id via NEXT_PUBLIC_METRIKA_COUNTER_ID (build-time)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-23 12:13:32 +05:00
parent 7bf3935c81
commit 0e67a53122
4 changed files with 34 additions and 0 deletions
+5
View File
@@ -16,6 +16,11 @@ S3_REGION="eu-central"
NEXT_PUBLIC_TURNSTILE_SITE_KEY="" NEXT_PUBLIC_TURNSTILE_SITE_KEY=""
TURNSTILE_SECRET_KEY="" TURNSTILE_SECRET_KEY=""
# Яндекс.Метрика — ID счётчика school.second-brain.ru (цели signup_free/gate_view).
# Build-time (NEXT_PUBLIC_*) — передавать через --build-arg при сборке. Сам счётчик
# (ym init snippet) ставится в admin → Settings → headCode, отдельно от этого ID.
NEXT_PUBLIC_METRIKA_COUNTER_ID=""
# Kinescope API # Kinescope API
KINESCOPE_API_KEY="" KINESCOPE_API_KEY=""
@@ -5,6 +5,7 @@ import Link from "next/link";
declare global { declare global {
interface Window { interface Window {
ym?: (counterId: number, action: string, goal: string) => void;
turnstile?: { turnstile?: {
render: ( render: (
container: HTMLElement, container: HTMLElement,
@@ -161,6 +162,11 @@ export function RegisterForm({ showTermsCheckbox, privacyPolicyUrl, termsUrl, of
return; return;
} }
// Яндекс.Метрика: цель «бесплатная регистрация»
const mc = Number(process.env.NEXT_PUBLIC_METRIKA_COUNTER_ID);
if (mc && typeof window !== "undefined" && typeof window.ym === "function") {
window.ym(mc, "reachGoal", "signup_free");
}
setSuccess(true); setSuccess(true);
setLoading(false); setLoading(false);
} }
@@ -0,0 +1,20 @@
"use client";
import { useEffect } from "react";
declare global {
interface Window {
ym?: (counterId: number, action: string, goal: string) => void;
}
}
// Фиксирует показ gate-лестницы в Яндекс.Метрике (цель gate_view).
export function GateViewTracker() {
useEffect(() => {
const c = Number(process.env.NEXT_PUBLIC_METRIKA_COUNTER_ID);
if (c && typeof window !== "undefined" && typeof window.ym === "function") {
window.ym(c, "reachGoal", "gate_view");
}
}, []);
return null;
}
@@ -2,6 +2,8 @@
// основной — трипвайр «Второй мозг для предпринимателя», вторичный — полный курс. // основной — трипвайр «Второй мозг для предпринимателя», вторичный — полный курс.
// Server component, ДС-2 (Aubade). // Server component, ДС-2 (Aubade).
import { GateViewTracker } from "./gate-view-tracker";
const TRIPWIRE_URL = "https://second-brain.ru/entrepreneur"; const TRIPWIRE_URL = "https://second-brain.ru/entrepreneur";
const FULL_COURSE_URL = "https://obsidian.second-brain.ru/"; const FULL_COURSE_URL = "https://obsidian.second-brain.ru/";
@@ -11,6 +13,7 @@ export function TripwireGateBanner() {
className="card-aubade p-6 mt-10" className="card-aubade p-6 mt-10"
style={{ background: "var(--accent)", boxShadow: "4px 4px 0 0 var(--foreground)" }} style={{ background: "var(--accent)", boxShadow: "4px 4px 0 0 var(--foreground)" }}
> >
<GateViewTracker />
<p <p
className="text-xs font-bold uppercase tracking-widest mb-2" className="text-xs font-bold uppercase tracking-widest mb-2"
style={{ color: "var(--muted-foreground)" }} style={{ color: "var(--muted-foreground)" }}