Counter Tracking / Collect API

Public, unauthenticated collect endpoints called by the 1.1 KB tracking snippet. GET /track records one aggregated visit (referrer, screen, country, language, device) keyed to a site data-id; POST /trackpage records a pageview via the browser Beacon API. No cookies or IP addresses are stored.

OpenAPI Specification

counter-dev-openapi.yml Raw ↑
openapi: 3.0.1
info:
  title: Counter API
  description: >-
    Counter (counter.dev) is an open-source, privacy-friendly web analytics
    service. This specification documents the real HTTP surface of the Counter
    server as implemented in the AGPL-3.0 source at
    https://github.com/ihucos/counter.dev. The tracking/collect endpoints are
    public and unauthenticated and are called by the browser tracking snippet.
    The stats endpoints return aggregated data and are protected either by a
    session cookie or by a user + token pair (sessionless, read-only). The
    account endpoints back the dashboard UI and are not a formally published
    developer API. Endpoint paths are derived directly from the server source;
    request/response schemas beyond the documented query parameters are not
    formally published by the project, so responses are described rather than
    fully schematized.
  termsOfService: https://counter.dev/
  contact:
    name: Counter (ihucos)
    url: https://github.com/ihucos/counter.dev
  license:
    name: AGPL-3.0
    url: https://github.com/ihucos/counter.dev/blob/master/LICENSE
  version: '1.0'
servers:
  - url: https://t.counter.dev
    description: Default hosted tracking / collect host (configurable via data-server).
  - url: https://counter.dev
    description: Hosted dashboard, stats, and account host. Self-hosted deployments use their own host.
paths:
  /track:
    get:
      operationId: track
      tags:
        - Tracking
      summary: Record an aggregated visit.
      description: >-
        Called by the tracking snippet ~4.5s after load, once per tab
        (guarded by a sessionStorage flag). Records a single aggregated visit
        for the site identified by the data-id. Requires an Origin header
        (used to derive the site id). No cookies are set and no IP address is
        stored; country may be supplied explicitly or derived from the
        CF-IPCountry header. Bots and localhost origins are ignored.
      parameters:
        - name: id
          in: query
          description: Site data-id (per-account cached UUID). Either id, user, or site must be provided.
          required: false
          schema:
            type: string
        - name: user
          in: query
          description: Account user id, used when id is not supplied.
          required: false
          schema:
            type: string
        - name: site
          in: query
          description: Legacy alias for the user/account id, supported for backward compatibility.
          required: false
          schema:
            type: string
        - name: referrer
          in: query
          description: Document referrer URL; only the host is retained.
          required: false
          schema:
            type: string
        - name: screen
          in: query
          description: Screen resolution as WIDTHxHEIGHT (bucketed to known resolutions or "Other").
          required: false
          schema:
            type: string
        - name: utcoffset
          in: query
          description: Client UTC offset, used to bucket the visit into the correct local day/hour.
          required: false
          schema:
            type: string
        - name: country
          in: query
          description: Two-letter country code; if omitted the CF-IPCountry header is used.
          required: false
          schema:
            type: string
      responses:
        '200':
          description: Visit recorded. Body is the plain text "OK".
          content:
            text/plain:
              schema:
                type: string
        '400':
          description: Bad request - missing site identifier or missing/invalid Origin header.
  /trackpage:
    post:
      operationId: trackpage
      tags:
        - Tracking
      summary: Record a pageview.
      description: >-
        Called by the tracking snippet via the browser Beacon API on every
        page load to record a pageview counter for the given path. Requires an
        Origin header. Body is application/x-www-form-urlencoded.
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              properties:
                id:
                  type: string
                  description: Site data-id (per-account cached UUID).
                page:
                  type: string
                  description: Page path (window.location.pathname).
      responses:
        '204':
          description: Pageview recorded. Empty body.
        '400':
          description: Bad request - missing or invalid Origin header.
  /query:
    get:
      operationId: query
      tags:
        - Stats
      summary: Query archived stats for a date range.
      description: >-
        Returns aggregated, archived visit data for the authenticated account
        over a date range as JSON. Authentication is by session cookie or by a
        user + token pair (sessionless, read-only). When demo=1 the magic demo
        account is queried instead.
      parameters:
        - name: from
          in: query
          description: Start date (YYYY-MM-DD).
          required: true
          schema:
            type: string
            format: date
        - name: to
          in: query
          description: End date (YYYY-MM-DD).
          required: true
          schema:
            type: string
            format: date
        - name: user
          in: query
          description: Account user id, for sessionless (token) access.
          required: false
          schema:
            type: string
        - name: token
          in: query
          description: Read-only API token for sessionless access (paired with user).
          required: false
          schema:
            type: string
        - name: demo
          in: query
          description: Set to 1 to query the public demo account.
          required: false
          schema:
            type: string
      responses:
        '200':
          description: Aggregated archive data for the requested range.
          content:
            application/json:
              schema:
                type: object
  /dump:
    get:
      operationId: dump
      tags:
        - Stats
      summary: Stream live and archived stats (Server-Sent Events).
      description: >-
        Opens a text/event-stream (Server-Sent Events) connection that pushes
        an initial archive payload and then live "dump" payloads (per-site
        counts, logs, and aggregated visits) as new visits arrive. Authenticated
        by session cookie, by user + token (sessionless), or via demo. This is
        the data feed the dashboard UI consumes; it is one-way HTTP streaming,
        not WebSocket.
      parameters:
        - name: utcoffset
          in: query
          description: Client UTC offset for day/hour bucketing.
          required: false
          schema:
            type: string
        - name: user
          in: query
          description: Account user id, for sessionless (token) access.
          required: false
          schema:
            type: string
        - name: token
          in: query
          description: Read-only API token for sessionless access (paired with user).
          required: false
          schema:
            type: string
        - name: demo
          in: query
          description: Set to a non-empty value to stream the public demo account.
          required: false
          schema:
            type: string
      responses:
        '200':
          description: Server-Sent Events stream of typed payloads (oldest-archive-date, archive, dump, nouser).
          content:
            text/event-stream:
              schema:
                type: string
  /resettoken:
    post:
      operationId: resetToken
      tags:
        - Account
      summary: Reset the account read token.
      description: >-
        Resets the authenticated account's read-only API token, invalidating
        the previous token. Requires an authenticated session.
      responses:
        '200':
          description: Token reset.
  /login:
    post:
      operationId: login
      tags:
        - Account
      summary: Log in and establish a session.
      description: >-
        Authenticates a user with username and password and sets a session
        cookie. Body is application/x-www-form-urlencoded.
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              required:
                - user
                - password
              properties:
                user:
                  type: string
                password:
                  type: string
      responses:
        '200':
          description: Logged in; session cookie set and account returned.
        '400':
          description: Missing input or wrong username/password.
  /register:
    post:
      operationId: register
      tags:
        - Account
      summary: Register a new account.
      description: >-
        Creates a new account with a username and password, optional email,
        and UTC offset preference, then establishes a session. Body is
        application/x-www-form-urlencoded.
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              required:
                - user
                - password
              properties:
                user:
                  type: string
                password:
                  type: string
                mail:
                  type: string
                utcoffset:
                  type: string
      responses:
        '200':
          description: Account created; session cookie set and account returned.
        '400':
          description: Missing input or account already exists.
  /logout:
    post:
      operationId: logout
      tags:
        - Account
      summary: Log out of the current session.
      responses:
        '200':
          description: Session cleared.
components:
  securitySchemes:
    sessionCookie:
      type: apiKey
      in: cookie
      name: session
      description: Session cookie set on login/register, used by the dashboard UI.
    apiToken:
      type: apiKey
      in: query
      name: token
      description: >-
        Read-only account token, paired with the user query parameter, for
        sessionless access to /query and /dump.