Гид по технологиям

Отслеживание просмотров страниц с помощью Supabase в Next.js

6 min read Веб-разработка Обновлено 09 Jan 2026
Отслеживание просмотров с Supabase и Next.js
Отслеживание просмотров с Supabase и Next.js

Коротко: этот материал показывает, как с помощью Supabase и Next.js отслеживать просмотры страниц без сторонних аналитических скриптов — создаём таблицу views, хранимую функцию update_views, API-маршрут и компонент счётчика просмотров. Включены варианты, чеклисты, советы по безопасности и примеры тестов.

График на экране ноутбука

Page views — важная метрика для оценки производительности сайта и интереса к материалам. Вместо сторонних скриптов (Google Analytics, Fathom) можно использовать собственную базу данных. Supabase — открытая альтернатива Firebase, предоставляющая Postgres, auth, instant API, Edge Functions и real-time подписки — подходит для подсчёта просмотров в реальном времени.

Что вы узнаете в этом руководстве

  • Как подготовить Next.js-проект к сбору просмотров.
  • Как создать таблицу views и хранимую функцию update_views в Supabase.
  • Как настроить клиент Supabase в Next.js и реализовать API-роут для увеличения/чтения счётчика.
  • Как подключить компонент ViewsCounter к страницам и регистрировать просмотры.
  • Дальше: расширение данных, безопасность, тесты и возможные альтернативы.

Подготовка сайта для отслеживания просмотров

Чтобы повторить шаги, у вас должен быть проект на Next.js. Если блога ещё нет, можно создать Markdown‑блог с react-markdown или клонировать официальный стартовый шаблон Next.js с GitHub.

Важно: подготовьте файл .env.local в корне проекта и не коммитьте в репозиторий секретные ключи.

Создаём базу данных Supabase

  1. Перейдите на сайт Supabase и войдите или зарегистрируйтесь.
  2. На панели управления нажмите кнопку “New Project” и выберите организацию (обычно создаётся автоматически под вашим именем пользователя).

Скриншот панели управления Supabase

  1. Заполните имя проекта и пароль, затем нажмите кнопку “Create new project”.

Скриншот деталей проекта в Supabase

  1. В разделе Settings → API скопируйте Project URL и публичный/секретный ключи (service key).

Скриншот API-ключей проекта Supabase

  1. Сохраните их в файл .env.local (локально):
NEXT_PUBLIC_SUPABASE_URL=""
NEXT_PUBLIC_SUPABASE_KEY=""
SUPABASE_SERVICE_KEY=""
  1. Перейдите в SQL editor и создайте таблицу views — можно выполнить SQL-запрос или воспользоваться table editor.

Редактор SQL в Supabase

Пример SQL для создания таблицы:

CREATE TABLE views (
  id bigint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
  slug text UNIQUE NOT NULL,
  view_count bigint DEFAULT 1 NOT NULL,
  updated_at timestamp DEFAULT NOW() NOT NULL
);

Или создайте те же поля вручную через графический редактор таблиц:

Колонки таблицы views в Supabase

Создаём хранимую функцию (Stored Procedure) для обновления просмотров

Postgres поддерживает SQL‑функции, которые удобно вызывать через Supabase RPC. Ниже — функция update_views, увеличивающая счётчик или создающая запись, если её нет.

  1. В SQL editor нажмите New Query.
  2. Вставьте и выполните запрос:
CREATE OR REPLACE FUNCTION update_views(page_slug TEXT)
RETURNS void
LANGUAGE plpgsql
AS $$
BEGIN
    IF EXISTS (SELECT FROM views WHERE slug = page_slug) THEN
        UPDATE views
        SET view_count = view_count + 1,
            updated_at = now()
        WHERE slug = page_slug;
    ELSE
        INSERT INTO views(slug) VALUES (page_slug);
    END IF;
END;
$$;
  1. Нажмите Run (или Ctrl/Cmd+Enter).

Пояснение: функция принимает slug публикации и увеличивает view_count на 1 или создаёт запись с дефолтным значением 1.

Важно: не давайте публичный service key в клиентском коде — используйте его на сервере (API-роуты, Edge Functions) или ограничивайте привилегии.

Настраиваем Supabase-клиент в Next.js

Установка пакета

В корне проекта установите официальный клиент:

npm install @supabase/supabase-js

Инициализация клиента

Создайте файл /lib/supabase.ts (или /lib/supabase/admin.ts если отделяете серверный клиент) и инициализируйте клиента:

import { createClient } from '@supabase/supabase-js';

const supabaseUrl: string = process.env.NEXT_PUBLIC_SUPABASE_URL || '';
const supabaseServerKey: string = process.env.SUPABASE_SERVICE_KEY || '';

const supabase = createClient(supabaseUrl, supabaseServerKey);

export { supabase };

Примечание: в примере выше используется серверный ключ. Для клиентских запросов используйте только NEXT_PUBLIC_SUPABASE_KEY.

Реализация API-роута для чтения и регистрации просмотров

Создайте файл /pages/api/views/[slug].ts (или в новой структуре /app/api) — он будет динамическим и получит slug из параметров.

import { supabase } from '../../../lib/supabase/admin';
import { NextApiRequest, NextApiResponse } from 'next';

const handler = async (req: NextApiRequest, res: NextApiResponse) => {
  if (req.method === 'POST') {
    await supabase.rpc('update_views', {
      page_slug: req.query.slug,
    });
    return res.status(200).json({ message: 'Success' });
  }

  if (req.method === 'GET') {
    const { data } = await supabase
      .from('views')
      .select('view_count')
      .filter('slug', 'eq', req.query.slug);

    if (data) {
      return res.status(200).json({ total: data[0]?.view_count || 0 });
    }
  }

  return res.status(400).json({ message: 'Invalid request' });
};

export default handler;

Пояснения:

  • POST вызывает RPC update_views и увеличивает счётчик (делайте это с клиента при загрузке страницы).
  • GET возвращает текущее значение view_count для указанного slug.
  • Важно: обрабатывать ошибки и rate-limit (см. раздел «Безопасность и надёжность»).

Компонент счётчика просмотров (ViewsCounter)

Установите swr для удобного получения данных с автоматическим обновлением:

npm install swr

Создайте компонент components/viewsCounter.tsx:

import useSWR from 'swr';

interface Props {
  slug: string;
}

const fetcher = async (input: RequestInfo) => {
  const res: Response = await fetch(input as string);
  return await res.json();
};

const ViewsCounter = ({ slug }: Props) => {
  const { data } = useSWR(`/api/views/${slug}`, fetcher);
  return {(data?.total) ? data.total : '0'} views;
};

export default ViewsCounter;

Этот компонент запрашивает текущее число просмотров и отображает его, пока swr обновляет данные в фоне.

Регистрируем просмотр при открытии страницы

В компоненте, который рендерит пост, вызовите POST к API при первой отрисовке:

import { useEffect } from 'react';
import ViewsCounter from '../../components/viewsCounter';

interface Props {
  slug: string;
}

const Post = ({ slug }: Props) => {
  useEffect(() => {
    fetch(`/api/views/${slug}`, { method: 'POST' });
  }, [slug]);

  return (
    
// blog content
); }; export default Post;

Проверьте панель Supabase — значение поля view_count должно увеличиваться при посещении страницы.

Когда этого подхода достаточно и когда он не подходит

  • Подходит когда: вы хотите минимальную собственную аналитику без внешних скриптов, нуждаетесь в контроле данных, хотите расширять структуру (рефереры, UTM, уникальные пользователи).
  • Не подходит когда: нужны сложные сегменты, отчёты по событиям, анонимизация по регламенту — в таких случаях удобнее готовые аналитические решения или смешанный подход.

Альтернативные подходы

  • Использовать готовые аналитические сервисы (Google Analytics, Plausible, Fathom) — быстро, но внешние скрипты.
  • Логировать просмотры на стороне CDN/серверов логов и агрегировать в ETL-пайплайне.
  • Хранить события просмотров в таблице events (аналог event sourcing) для гибкой аналитики.

Модель принятия решения (умозрительная)

  • Нужна ли вам полнота данных и сегменты? Если да — используйте аналитический инструмент.
  • Нужен ли полный контроль и гибкость? Если да — Supabase/Postgres подойдёт.
  • Требуется ли низкая задержка и real-time? Supabase поддерживает real-time подписки.
flowchart TD
  A[Начало] --> B{Нужна аналитика}
  B -->|Минимальная| C[Supabase: таблица views]
  B -->|Продвинутая| D[GA/Fathom/Plausible]
  C --> E{Требуется сегментация}
  E -->|Да| F[Добавить таблицу events и UTM]
  E -->|Нет| G[Оставить views и dashboard]

Факто-бокс: ключевые элементы

  • Хранилище: Supabase (Postgres).
  • Таблица: views {id, slug, view_count, updated_at}.
  • RPC: update_views(page_slug TEXT).
  • API: /api/views/[slug] — GET (получить), POST (увеличить).
  • Клиент: swr для чтения, fetch POST для регистрации.

Чеклист ролей

Developer:

  • Создать таблицу views.
  • Написать функцию update_views.
  • Настроить API-роут и компонент ViewsCounter.
  • Написать тесты на API.

DevOps / SRE:

  • Защитить service key, настроить секреты в CI.
  • Настроить бэкап базы данных.
  • Настроить rate-limits и мониторинг ошибок.

Product / PM:

  • Определить, какие метрики нужны (просмотры, рефералы, UTM).
  • Решить период хранения и правила удаления данных.

Безопасность и приватность (GDPR и права доступа)

Важно:

  • Не храните в счётчике персональные данные (PII) без явного основания.
  • Если собираете IP или реферер, укажите это в политике конфиденциальности и при необходимости обеспечьте согласие пользователей.
  • Храните service key в защищённых секретах (Vercel/Netlify/CI) и не публикуйте его в клиентском коде.

Тесты и критерии приёмки

Критерии приёмки:

  • POST /api/views/:slug увеличивает view_count на 1.
  • GET /api/views/:slug возвращает корректное значение total.
  • Повторные запросы от одного клиента корректно увеличивают счётчик (поведение определяется вами).
  • Секреты не присутствуют в публичном репозитории.

Минимальные тест-кейсы:

  • Создать запись через POST и проверить view_count == 1.
  • Повторить POST и проверить view_count == 2.
  • GET на несуществующий slug возвращает total: 0.
  • Неподдерживаемый метод возвращает 400.

Отладка и распространённые проблемы

  • Ничего не меняется в базе: проверьте, использует ли API правильный service key и подключение к корректному проекту Supabase.
  • CORS и ошибки сети: убедитесь, что запросы с клиентской части идут на ваш API-роут, а не напрямую в Supabase приватной частью.
  • Конкурентность: если ожидается очень большой трафик, подумайте о атомарных операциях в базе или использовании инкрементов на уровне SQL.

Шаблон расширения: отслеживание реферера и UTM

Если хотите хранить источник трафика, создайте отдельную таблицу referrers или расширьте events:

  • Таблица referrers: id, slug, referrer text, utm_source text, utm_medium text, created_at timestamp.
  • Каждый POST может посылать дополнительные поля (referrer, utm) на сервер, где вы сначала валидируете данные, затем вставляете запись и вызываете update_views.

Когда не стоит изобретать велосипед

Если вам нужны готовые панели, сегментация, экспорт данных в BigQuery и сложная аналитика — используйте готовые аналитические решения. Собственная реализация хороша, когда важен контроль и минимальный набор метрик.

Краткое резюме

  • Supabase + Next.js дают простой путь для собственной системы подсчёта просмотров.
  • Архитектурно: таблица views + RPC update_views + API-роут + клиентский компонент.
  • Дополнительно продумайте безопасность ключей, приватность пользователей и тестирование.

Важно: начните с минимальной рабочей реализации, затем расширяйте (рефереры, UTM, события) по мере потребностей.

Глоссарий (одна строка):

  • slug — уникальный короткий идентификатор страницы, обычно в URL.
Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

RDP: полный гид по настройке и безопасности
Инфраструктура

RDP: полный гид по настройке и безопасности

Android как клавиатура и трекпад для Windows
Гайды

Android как клавиатура и трекпад для Windows

Советы и приёмы для работы с PDF
Документы

Советы и приёмы для работы с PDF

Calibration в Lightroom Classic: как и когда использовать
Фото

Calibration в Lightroom Classic: как и когда использовать

Отключить Siri Suggestions на iPhone
iOS

Отключить Siri Suggestions на iPhone

Рисование таблиц в Microsoft Word — руководство
Office

Рисование таблиц в Microsoft Word — руководство