Перейти до вмісту

Documentation

Інтеграція та формат даних IntentD

Технічні специфікації для розробників розширень і дата-інженерів на боці покупця. Усе, що потрібно, щоб почати надсилати події або читати вигрузки.

Manifest V3 HMAC-SHA256 X25519 + AES-GCM Parquet + LZ4 PII-free

01 · Publishers

SDK Quickstart

SDK працює в background script розширення і не потребує доступу до DOM сторінки. Бандл збирається в кабінеті персонально для розширення: ключі, ключ шифрування та ID розширення вже всередині, викликати init вручну не потрібно. До згоди користувача SDK нічого не збирає — як влаштований запит згоди.

bash
# Кабінет → Розширення → SDK → Завантажити
# Файл intentd-<name>.min.js уже містить ключі та конфігурацію.
cp ~/Downloads/intentd-my-extension.min.js ./extension/intentd.min.js
background.js
// background.js — першим рядком, на верхньому рівні.
// init викликається автоматично; слухачі мають реєструватися
// при старті service worker, інакше Manifest V3 не доставить події.
import './intentd.min.js';

// Необов'язково: статус і ручне надсилання.
// const status = await IntentD.status();
// await IntentD.flush();

Вимоги до маніфесту

  • manifest_version: 3 — SDK не використовує eval і не підвантажує код ззовні.
  • storage, alarms, unlimitedStorage — події накопичуються локально й ідуть пакетом раз на добу.
  • webNavigation (або tabs) — джерело подій навігації.
  • api.intentd.io у host_permissions.

Перед завантаженням вкажіть у кабінеті ID розширення з магазину: бандл відмовляється працювати всередині будь-якого іншого розширення і повідомляє про це.

02 · Publishers

Ingest API

Base URL
https://api.intentd.io/v1
Автентифікація
X-API-Key + HMAC-SHA256 по тілу

Ендпоінти

Метод Шлях Призначення Ліміт
POST /sdk/register Реєстрація установки: сесія та ідентифікатор пакета. Ідемпотентна. 120 запитів / хв з IP
POST /telemetry/bucket Зашифрований пакет подій (X25519 + AES-256-GCM). Раз на добу або достроково. 48 пакетів / добу на установку
POST /sdk/report-tamper Повідомлення SDK про провалену перевірку цілісності. 30 запитів / хв з IP

Приклад запиту

http
POST /v1/telemetry/bucket HTTP/1.1
Host: api.intentd.io
Content-Type: application/json
X-API-Key: ext_...
X-Timestamp: 1758000000
# hex(HMAC-SHA256(secret, "intentd-v2|bucket|<X-Timestamp>|<X-API-Key>|" + hex(SHA-256(body))))
X-Signature: d49d3b20...

{
  "bucket_id": "7c0e…", "session_id": "2b91…",
  "ephemeral_public_key": "base64(32 байти)",
  "iv": "base64(12 байтів)",
  "encrypted_key": "base64(48 байтів)",
  "ciphertext": "base64(AES-256-GCM пакета INTD)",
  "events_count": 1234, "bytes_size": 45678, "bucket_version": 1,
  "client_ts": 1758000000, "fingerprint_hash": "5c9a96…"
}

Коди помилок

HTTP Код Значення
400 BUCKET_INVALID_FORMAT Пакет не розшифрувався або не пройшов перевірку формату і CRC32
401 API_KEY_REVOKED Ключ відкликано — SDK вимикається
401 INVALID_SIGNATURE HMAC-підпис не збігся з тілом запиту
401 CLOCK_SKEW Годинник клієнта розходиться більше ніж на 5 хвилин; у відповіді server_time
402 SUBSCRIPTION_INACTIVE Немає активної підписки — події залишаються в черзі
403 WRONG_EXTENSION Бандл запущено не в тому розширенні, для якого його випущено
403 FINGERPRINT_MISMATCH Оточення не збігається з сесією — SDK реєструється заново
409 BUCKET_ALREADY_RECEIVED Цей пакет уже прийнято
413 BUCKET_TOO_LARGE Більше ніж 10 000 подій або 10 МБ — SDK ділить пакет
429 RATE_LIMITED Перевищено ліміт запитів або пакетів на добу

На мережевих помилках, 429 і 503 SDK зберігає чергу й повторює надсилання раз на годину. Двійковий формат пакета та схема шифрування описані відкрито — специфікація INTD v1.

03 · Data Buyers

Схема даних

Один рядок Parquet — одна очищена подія. Полів із персональними даними в схемі немає за побудовою: вони відкидаються в браузері, до надсилання.

Поля події у вигрузці Parquet
Поле Тип Опис
event_id String Унікальний GUID події
timestamp Int64 Unix Timestamp у мілісекундах, UTC
anon_uid String HMAC-хеш сесії користувача, незворотний
clean_url String URL після вирізання PII-параметрів
search_query String Витягнутий пошуковий інтент, якщо він є
lang String Мова браузера, BCP 47
geo_country String ISO-код країни, визначається за IP на edge growth+
device_type String desktop / mobile / tablet growth+
domain String Кореневий домен без піддоменів

Data Buyers

Data Provenance

  • Усі події надходять лише від користувачів, які явно натиснули «Дозволити» в запиті згоди (GDPR ст. 6(1)(a)). До згоди SDK не створює ідентифікатор і не зберігає події.
  • Кожен прийнятий пакет несе версію тексту згоди; сервер відхиляє пакети без неї і фіксує версію в журналі прийому. При зміні тексту згоду запитують заново.
  • При відкликанні згоди SDK припиняє збір і видаляє ненадіслані події на пристрої; наступна видача згоди створює новий, не пов’язаний із попереднім псевдонім.
  • Факт і час згоди конкретного користувача на сервері не зберігаються: доказом слугує сам прийнятий пакет і зафіксована версія тексту.

04 · Data Buyers

Зберігання і доставка

Формат
Parquet + LZ4
Сховище
AWS S3
Hot-доступ
30 днів
Архів
90 днів

Структура шляхів

s3
year=YYYY/month=MM/day=DD/tenant=<key_id>__<bucket_id>.parquet.lz4

Партиціонування за датою та орендарем дозволяє читати потрібний зріз без повного сканування бакета. Growth і вище додатково підтримують синхронізацію у ваш власний bucket.

05 · Data Buyers

Приклади читання

Вигрузка читається будь-яким стандартним Parquet-стеком. Нижче — мінімальні приклади на Python і Go.

python
import pandas as pd

# Денна партиція орендаря в S3.
path = "s3://intentd-delivery/year=2026/month=09/day=11/tenant=ext_acme__7c0e.parquet.lz4"

frame = pd.read_parquet(
    path,
    columns=["timestamp", "domain", "search_query", "geo_country"],
    storage_options={
        "key": "YOUR_ACCESS_KEY",
        "secret": "YOUR_SECRET_KEY",
    },
)

top_domains = frame.groupby("domain").size().sort_values(ascending=False).head(20)
print(top_domains)
go
package main

import (
    "context"
    "log"

    "github.com/aws/aws-sdk-go-v2/config"
    "github.com/aws/aws-sdk-go-v2/service/s3"
)

func main() {
    ctx := context.Background()

    cfg, err := config.LoadDefaultConfig(ctx)
    if err != nil {
        log.Fatal(err)
    }

    client := s3.NewFromConfig(cfg)

    object, err := client.GetObject(ctx, &s3.GetObjectInput{
        Bucket: ptr("intentd-delivery"),
        Key:    ptr("year=2026/month=09/day=11/tenant=ext_acme__7c0e.parquet.lz4"),
    })
    if err != nil {
        log.Fatal(err)
    }
    defer object.Body.Close()

    // Далі — будь-який Parquet-рідер, наприклад parquet-go.
    log.Printf("отримано %d байтів", *object.ContentLength)
}

func ptr(s string) *string { return &s }

Готові підключитися?

Створіть акаунт, щоб отримати ключі та зарезервувати вигрузку. Якщо потрібен семпл даних до підписання — напишіть нам.

Повна OpenAPI-специфікація порталу лежить у репозиторії: portal/docs/swagger.yaml. Публічний hosted-варіант з’явиться разом з особистим кабінетом — повідомити про потребу.