Documentație

Un singur script, și tot ce deblochează.

PageView.ro colectează printr-un singur script asincron, de circa 2,5KB gzip. Pagina aceasta documentează exact ce trimite, ce atribute opționale activează rapoartele pe autor, categorie și vizitatori care revin, ce pune pluginul WordPress în wp-admin și cum citești aceleași cifre prin API-ul public.

Pasul 1

Instalarea trackerului

Pui un singur script în <head>-ul fiecărei pagini. Nu mai ai nimic de configurat în browser — fără apel de inițializare, fără dependințe.

Un singur script, ~2,5KB gzip
<script defer src="https://t.pageview.ro/tracker.v1.js"
        data-site="pk_your_public_key"></script>
  • data-site

    Cheia publică a site-ului (pk_…), copiată din dashboard, secțiunea Settings → Install & tracking. Identifică site-ul și nu dă niciun drept de citire, deci poate sta liniștit în HTML public. Nu se rotește niciodată — schimbarea ei ar rupe fiecare script instalat.

  • Unde se pune

    În <head>, pe fiecare pagină, de preferat înaintea celorlalte scripturi de analytics sau de reclame. Scriptul este defer și fără dependințe, deci nu blochează randarea.

  • Dimensiune

    5.314 octeți bruți, 2.565 octeți gzip — circa 2,5KB pe fir. Build-ul eșuează dacă bundle-ul depășește bugetul de 20KB gzip, deci nu poate crește pe nesimțite.

  • Transport

    Întâi sendBeacon, apoi fetch cu keepalive ca rezervă, pentru toate tipurile de eveniment. Corpul pleacă drept text/plain — un content type din lista sigură CORS — deci browserul nu face niciodată cerere de preflight.

  • Răspunsuri

    202 când evenimentul e acceptat, 204 când e respins (cheie necunoscută, origine nepermisă, limită de rată). Niciodată 4xx/5xx pe care browserul cititorului să le gestioneze, iar trackerul înghite orice eroare în loc s-o arunce în pagina ta.

  • Cât durează până apar datele

    Primul beacon de pageview pleacă imediat ce se execută scriptul — nu e amânat după requestIdleCallback. Tabloul realtime primește un snapshot nou la circa două secunde, iar un cititor e considerat activ într-o fereastră de 30 de secunde, întreținută de un heartbeat fix la 10 secunde.

  • Aplicații single-page

    history.pushState / replaceState, popstate și hashchange sunt interceptate: o schimbare reală de rută trimite un pageview nou, schimbările doar de hash sunt ignorate, iar o revenire din bfcache (Înapoi/Înainte) retrimite unul.

  • Reîncărcările

    Reîncărcarea aceleiași căi, în același tab, în mai puțin de 30 de minute înseamnă prezență, nu consum nou: primul beacon devine heartbeat, deci cititorul rămâne live, iar vizita nu se numără de două ori.

  • Restricționarea originilor

    Settings → Install & tracking → Allowed domains limitează colectarea la host-urile pe care le listezi. Lăsată goală, colectarea acceptă evenimente de la orice origine care folosește cheia ta publică.

Verifică rapid că funcționează

Încarcă site-ul cu DevTools deschis pe tabul Network și caută cererile către t.pageview.ro/api/event — un 202 înseamnă că evenimentul a fost acceptat. Pagina ar trebui să apară pe tabloul live în câteva secunde.

Pasul 2

Atribute opționale ale scriptului

Doar data-site este obligatoriu. Tot ce urmează este opțional și aditiv: dacă adaugi un atribut, activezi un raport; dacă îl lași afară, nimic altceva nu se schimbă în comportamentul trackerului.

Atribute opționale ale scriptului
AtributCe activează
data-siteobligatoriuCheia publică a site-ului. Fără ea scriptul nu face absolut nimic.
data-authorSemnătura articolului. Alimentează clasamentul Autori și filtrul pe autor. Călătorește cu pageview-ul; ping-urile o moștenesc pe server.
data-sectionCategoria paginii — câmpul de pe fir și coloana se numesc în continuare section, rapoartele îi spun categorie. Alimentează clasamentul Categorii și filtrul pe categorie.
data-articleId-ul tău de articol, stocat lângă cale. Util când potrivești rândurile din analytics cu înregistrările din CMS.
data-personIdentitatea first-party opt-in — snippetul din dashboard emite data-person="1". Activează raportul „nou vs. revenit” și are efect doar dacă opțiunea per site este pornită. Stochează un id în localStorage și într-un cookie, deci consimțământul rămâne în sarcina ta (vezi secțiunea de confidențialitate).
data-canonicalTransformă scriptul în marker de sindicalizare, nu în tracker. Pe domeniul tău nu face nimic; pe un host străin care ți-a republicat HTML-ul trimite exact un beacon de sindicalizare — fără identitate, fără ping-uri — care apare în caseta Aggregators.
data-endpointSchimbă endpointul de colectare. Implicit https://t.pageview.ro/api/event; îți trebuie doar pentru o colectare prin proxy sau găzduită de tine.
Pagină de articol, cu metadate editoriale
<script defer src="https://t.pageview.ro/tracker.v1.js"
        data-site="pk_your_public_key"
        data-author="Ana Pop"
        data-section="politics"
        data-article="12345"></script>

Dacă tema nu poate adăuga atribute pe tagul de script, trackerul citește aceleași trei valori din meta taguri:

Aceleași valori, ca meta taguri
<meta name="afm:author"  content="Ana Pop">
<meta name="afm:section" content="politics">
<meta name="afm:article" content="12345">

Detecție automată

Când lipsesc și atributul, și meta tagul, trackerul completează singur autorul și categoria, în această ordine:

  1. 01<meta name="author"> și <meta property="article:section"> — exact ce scot deja Yoast și Rank Math.
  2. 02JSON-LD schema.org: author.name și articleSection.
  3. 03clasa de body WordPress category-<slug>.

Așa că un site de știri pe WordPress raportează autorul și categoria fără nicio modificare de markup. Titlul se ia din document.title (trunchiat la 200 de caractere) și nu cere nici el markup.

Cum excluzi un cititor

  • Global Privacy Control: dacă browserul setează navigator.globalPrivacyControl, trackerul nu trimite nimic.
  • localStorage: setarea afm_optout pe „1” are același efect. window.__afm.optout() o scrie pentru tine și are efect imediat, pentru toate scripturile din pagină.
  • În configurația implicită nu ai ce cookie să ștergi — trackerul nu setează niciunul.

Evenimente personalizate

Înregistrează un eveniment personalizat
window.__afm.track("video-played", { quartile: "50" });
  • window.__afm.track(name, props?) înregistrează un eveniment ales de tine (o redare video, o înscriere, atingerea unui paywall). Nu aruncă niciodată eroare, iar apelurile făcute după ce tag-ul a rulat, dar înainte de trimiterea primului pageview, sunt puse într-o coadă și livrate automat.
  • window.__afm există doar după ce tag-ul (deferred) s-a executat — codul care ar putea rula mai devreme fie protejează apelul (window.__afm && window.__afm.track(...)), fie lipește acest stub de o linie înaintea lui: window.__afm = window.__afm || { q: [], track(n, p) { if (this.q.length < 20) this.q.push([n, p]); } }; — trackerul preia coada stub-ului la încărcare (nu adăuga un stub de optout: cel real nu s-ar mai instala).
  • name trebuie să fie minuscul și să respecte ^[a-z0-9][a-z0-9_.:-]{0,63}$ — orice altceva este ignorat silențios, nu se trimite.
  • props este opțional: perechi cheie → valoare simple (șirurile, numerele și boolean-ii sunt transformate în text), maximum 10 intrări, 32 de octeți per cheie, 200 de octeți per valoare.
  • Sunt acceptate până la 60 de evenimente per vizualizare de pagină; evenimentele personalizate nu poartă niciodată identitatea first-party a vizitatorului și deocamdată nu sunt pe API-ul public de citire.
Citește ghidul complet — referință API, șase rețete gata de folosit, limite
WordPress

Pluginurile WordPress

Next Stage Analytics leagă site-ul WordPress de PageView.ro prin cheia API a site-ului și duce cifrele acolo unde lucrează deja redactorii — în wp-admin. Toate apelurile către PageView.ro se fac server-side, în PHP; browserul vorbește doar cu propriul tău WordPress.

  • Coloana „Trafic” în lista de articole

    Adaugă o coloană de trafic în Articole → Toate articolele (edit.php), cu traficul total al fiecărui articol publicat pe ultimele ~400 de zile. Valorile se completează asincron, deci lista nu așteaptă niciodată după apelul extern; articolele nepublicate afișează o liniuță.

  • „Trafic azi” în bara de administrare

    Un indicator în dreapta barei de administrare, cu afișările de azi pentru ziua locală a site-ului, completat asincron și cache-uit scurt (~2 minute). Click pe el deschide dashboard-ul PageView.ro.

  • Widget în Panoul de control

    În Panoul de control din wp-admin: traficul de azi, un grafic SVG inline pe ultimele 7 zile (fără librării externe) și top 5 articole ale săptămânii, fiecare cu link. Se randează instant, cu placeholdere, și se completează dintr-o singură cerere compusă, cache-uită ~10 minute.

  • Metabox în editorul de articole

    O casetă „Trafic articol” în bara laterală — identică în Gutenberg și în editorul clasic — cu afișări și vizitatori pe ultimele 24 de ore, 7 zile și 30 de zile, plus top surse de trafic pe 7 zile. Articolele nepublicate nu generează niciun apel către API.

  • Injectarea trackerului (opțional)

    Pluginul poate adăuga singur scriptul de urmărire în <head>, cu cheia publică pk_, pentru site-urile care nu au deja snippetul în temă. Pe un articol adaugă și data-author / data-section direct din WordPress — autorul real și categoria principală (categoria primară Yoast, dacă e setată, altfel prima atribuită) — valori pe care trackerul le preferă în locul detecției client-side.

  • Marker pentru AI și agregatoare (opțional)

    Inserează în articolele publicate o notă de atribuire ascunsă plus un script cu data-canonical. Copiile republicate cu HTML-ul intact apar apoi în caseta Aggregators din dashboard. E best-effort prin construcție: feed-urile RSS sunt excluse, iar un agregator care elimină scripturile nu poate fi detectat pe această cale.

Manșeta live — shortcode-ul [pageview]

O bandă live, pentru cititori, pe care o pui direct în articol: câți sunt pe site acum, câți au citit articolul azi, vizitatori azi și vizitatori luna aceasta, plus badge-ul „Powered by PageView.ro”. Dacă pluginul nu e configurat, shortcode-ul nu randează nimic.

Exemple
[pageview]
[pageview show="live,articol" lang="en"]
[pageview show="total,live"]
  • show

    Listă separată prin virgulă din live, articol, total, luna, în ordinea dorită (implicit toate patru). Sinonime: article ≡ articol, azi/today ≡ total, month/monthly ≡ luna. Token-urile necunoscute sunt ignorate, iar metrica articol apare doar pe paginile singulare.

  • lang

    ro (implicit) sau en — limba etichetelor.

  • design

    Acceptat, dar deocamdată ignorat; există un singur design, iar atributul e rezervat pentru variante viitoare.

  • Cache

    Fiecare metrică e cache-uită pe server (live 15s, azi 60s, articol 120s, lună 300s), cu protecție anti-stampede. După încărcare doar cifra „live” se reîmprospătează în pagină, și doar cât timp tabul e vizibil — fără cifre inventate între refresh-uri.

Unde stă cheia API

  • Cheia API pv_ e ținută în opțiunile WordPress și folosită doar din PHP. Browserul vorbește cu propriul tău site — admin-ajax sau o rută dedicată, mai ușoară — niciodată direct cu PageView.ro.
  • Cheia publică de tracker (pk_) e o setare separată, iar sanitizarea respinge orice valoare care nu e o cheie pk_, deci cheia secretă de citire nu poate ajunge din greșeală într-o pagină publică.
  • Dacă pluginul nu e configurat sau API-ul nu răspunde, pur și simplu nu se randează nimic — fără erori vizibile pe front-end și fără ecrane blocate în admin.

Cerințe

  • WordPress 5.6+ și PHP 7.4+.
  • O cheie API a site-ului din Settings → API access, plus URL-ul de bază al API-ului (implicit https://app.pageview.ro).
  • Pluginul Next Stage Schedule doar dacă vrei badge-urile de trafic în calendarul lui Social Schedule; restul funcțiilor merg de sine stătător.
  • Pluginul se distribuie direct, nu prin directorul WordPress.org.

Next Stage Cross (opțional)

Un plugin complementar pentru rețele de publisheri. Când un articol trece de pragul de cititori live pe care îl stabilești, PageView.ro trimite un webhook semnat HMAC către alt site din rețea, care verifică semnătura și importă articolul — cu un registru „exact o dată”, deci un articol evergreen nu se retrimite niciodată. E un plugin separat și complet opțional; nimic din rapoartele de mai sus nu depinde de el.

API

API-ul public de citire

Fiecare raport istoric pe care îl desenează dashboard-ul poate fi citit și prin HTTP, cu o cheie per site. Doar citire, fără sesiune de dashboard — e exact API-ul folosit de pluginul WordPress.

Autentificare

  • Un administrator al site-ului generează cheia în Settings → API access (Generate / Regenerate / Revoke). Arată ca pv_… și este un secret: cine o are poate citi statisticile acelui site.
  • O trimiți în antetul x-api-key: pv_… sau ca authorization: Bearer pv_….
  • Cheia corespunde exact unui singur site. Nu există parametru site_id de trimis, deci o cheie scursă nu poate atinge datele altui site.
  • URL-ul de bază este originea dashboard-ului tău — https://app.pageview.ro — și e afișat lângă cheie.
API-ul public de citire
EndpointCe întoarce
GET /api/v1/timeseriesAfișări, vizitatori unici și secunde de lectură pe minut, oră sau zi. granularity=total întoarce un singur rând agregat pentru toată fereastra.
GET /api/v1/pagesTop pagini: cale, id de articol, titlu, afișări, vizitatori, media secundelor de lectură și adâncimea medie de scroll.
GET /api/v1/sourcesTrafic pe canal și pe domeniu referrer. Cu granularity=hour|day devine o serie „canale în timp”.
GET /api/v1/breakdownCompoziția audienței pe interval: țări, împărțirea pe dispozitive și UTM source/medium/campaign. Doar JSON.
GET /api/v1/authorsTotaluri pe semnătură: afișări, vizitatori, media secundelor de lectură și numărul de articole distincte.
GET /api/v1/categoriesAceleași cifre, pe categorie.
GET /api/v1/returningCititori noi vs. reveniți pe interval. Cere identitatea first-party opt-in; întoarce zerouri când e oprită.
GET /api/v1/live{ "concurrents": n } — cititorii de pe site chiar acum, cu aceeași definiție ca tabloul realtime.
Afișări pe ore, pentru o zi
curl -s -H "x-api-key: pv_your_api_key" \
  "https://app.pageview.ro/api/v1/timeseries?from=1782864000&to=1782950400&granularity=hour"
Răspuns
[
  { "t": 1782864000, "pageviews": 1200, "visitors": 800, "engaged_sec": 54321 },
  { "t": 1782867600, "pageviews": 940,  "visitors": 612, "engaged_sec": 41180 }
]

Parametri care contează

  • from / to

    Secunde Unix, interval semideschis [from, to). Obligatorii la toate rapoartele, mai puțin live, cu to mai mare decât from și un interval de cel mult 400 de zile.

  • granularity

    Obligatoriu la timeseries: minute | hour | day | total. Opțional la sources, unde hour | day comută răspunsul pe seria „canale în timp” (minute și total sunt respinse acolo).

  • limit

    La pages, authors și categories. Authors și categories sunt plafonate la 100 de rânduri.

  • precise=1

    Forțează citirea exactă din evenimentele brute, în loc de agregările precalculate. Merită pe intervale scurte și recente — și pe orice fereastră glisantă care nu e aliniată la oră, unde agregarea orară ar pierde contribuția parțială a bucketului mai vechi.

  • Filtre de scop

    author, category, article, source, country, device, utm_source, utm_medium și utm_campaign la timeseries, pages, sources și breakdown. Se combină cu ȘI, iar orice filtru comută raportul pe evenimente brute — deci rezultatele merg în urmă cel mult 90 de zile.

  • format=csv

    La timeseries, pages, sources, authors și categories. breakdown, returning și live sunt doar JSON.

Erori

  • 401 — cheia lipsește sau e invalidă.
  • 404 — numele raportului nu e unul dintre cele opt de mai sus.
  • 400 — intervalul lipsește sau e invalid (to trebuie să fie mai mare decât from, iar intervalul de cel mult 400 de zile) ori granularity lipsește / e invalid acolo unde e obligatoriu.
  • Orice altceva este statusul propriu al backendului de raportare, transmis nemodificat.
Confidențialitate și limite

Ce se colectează, ce se păstrează

Configurația implicită este fără cookie-uri. Citește secțiunea înainte de implementare — două dintre punctele de mai jos sunt limite, nu funcții, și schimbă felul în care trebuie citite cifrele.

  • Fără cookie-uri, implicit

    Id-ul de vizitator este un SipHash peste user agent, adresă IP și domeniu, calculat cu o sare care se rotește la miezul nopții UTC. IP-ul brut și user agentul brut nu sunt niciodată păstrate, nu se setează niciun cookie și nu există urmărire între site-uri.

  • Ce duce un eveniment

    Calea din URL, referrerul, clasa de dispozitiv, browserul, o țară derivată pe server din IP și metadatele editoriale pe care alegi să le trimiți (autor, categorie, titlu, id de articol). Fără nume, fără adrese de e-mail, fără text liber cu date personale.

  • Identitate first-party, opt-in

    person_id (afm_pid) se activează per site și este oprit implicit. Stochează un id first-party în localStorage și într-un cookie, deci nu mai este „fără cookie-uri”: conform ePrivacy, tu ești operatorul și obținerea consimțământului îți revine — noi prelucrăm în numele tău. Id-ul din browser se regenerează după 365 de zile.

  • Excluderea cititorului

    Global Privacy Control și indicatorul afm_optout sunt respectate de tracker. Un cititor exclus nu trimite absolut nimic — nici pageview, nici heartbeat.

  • Ștergere

    Datele de analytics pot fi șterse pentru un singur id de persoană sau pentru un site întreg, din evenimentele brute, din agregări și din profilurile de vizitator.

Retenție

Retenție
DateSe păstrează
Evenimente brute — ce citește orice raport filtrat sau „precise”90 de zile
Totaluri de site pe minut13 luni
Agregări orare pe pagini și pe surse25 de luni
Profiluri de vizitator — doar cu identitatea first-party opt-in18 luni
Accesări ale boților care execută JavaScript30 de zile
Detecții de sindicalizare / agregatoare90 de zile

Limite bune de știut din start

  • Vizitatorii unici pe intervale lungi sunt aproximativi

    Din două motive: rapoartele pe bucketuri numără unicii cu o structură aproximativă, iar id-ul fără cookie-uri primește o sare nouă la fiecare miez de noapte UTC, deci o persoană care revine în trei zile se numără de trei ori. Intervalele scurte și recente se citesc exact din evenimentele brute; identitatea exactă între zile cere identitatea first-party opt-in.

  • Unele rapoarte nu văd mai vechi de 90 de zile

    Rapoartele pe autori, categorii, audiență, pe articol și pe agregatoare citesc evenimentele brute — agregările nu poartă acele dimensiuni — deci sunt limitate la fereastra de 90 de zile și marchează partial: true când intervalul cerut începe mai devreme. Totalurile de afișări și de surse merg în urmă 25 de luni.

  • Se văd doar boții care execută JavaScript

    Un crawler care nu rulează niciodată scriptul nu ajunge la colectare, deci raportarea pe boți acoperă exclusiv boții cu JavaScript. Boții recunoscuți sunt ținuți în afara oricărei metrici umane și stocați separat.

  • Reîncărcările nu sunt, intenționat, pageview-uri

    Reîncărcarea aceleiași căi, în același tab, în mai puțin de 30 de minute păstrează cititorul live fără să înregistreze un al doilea pageview. E intenționat — așa rămân onești cititorii simultani — dar e o diferență reală față de instrumentele care numără fiecare încărcare.

Vrei o cheie cu care să încerci?

Accesul timpuriu este momentan pe bază de invitație. Cere acces și îți punem tabloul pe direct.