Configuration

Config file

Create a velocirepo.toml in your project root:

[projects.my-project]
name = "My Project"
github = "owner/repo"
github-traffic = "owner/repo"
pypi = "my-package"

[projects.other-project]
name = "Other Project"
github = ["owner/other", "owner/other-utils"]
cran = "other"
homebrew = "other"
youtube = "@ChannelHandle"
linkedin = "urn:li:organization:123456"

Each source field accepts either a single string or an array of strings, so you can track multiple repositories or packages under one project.

The github-traffic source fetches daily page views and clone counts. GitHub only retains this data for 14 days, so velocirepo preserves it before it’s lost. It requires a token with Administration:read permission (or the repo scope for classic tokens).

Or initialize one interactively (auto-detects sources from your repository):

velocirepo init

velocirepo looks for velocirepo.toml by walking up from the current directory. Override with --config or the VELOCIREPO_CONFIG environment variable.

Authentication

velocirepo uses API tokens to authenticate with external services. Tokens can be provided in three ways:

  1. Environment variables — export them in your shell (e.g., export GITHUB_TOKEN=ghp_...)
  2. .env file — place a .env file next to your velocirepo.toml; variables are loaded automatically
  3. GitHub Actions secrets — when using velocirepo install-ci or the GitHub Action, pass tokens as secrets (see Installation)
Variable Required for How to get one
GITHUB_TOKEN GitHub Events, GitHub Traffic Create a personal access token — use a fine-grained token with Contents:read (add Administration:read for traffic data)
PLAUSIBLE_TOKEN Plausible Create an API key in your Plausible site settings
YOUTUBE_TOKEN YouTube Create an API key in the Google Cloud Console with the YouTube Data API v3 enabled
LINKEDIN_TOKEN LinkedIn Run velocirepo auth linkedin after creating a LinkedIn app; see LinkedIn OAuth setup
VELOCIREPO_CONFIG — Path to config file (not a token, but supported as an env var)

Supported sources

Source What it tracks
GitHub Events Individual events (forks, issues, PRs, comments) with user and timestamp, plus daily and total stars
GitHub Traffic Daily page views and git clones (requires admin access)
PyPI Daily download counts
CRAN Daily download counts
Homebrew Install counts (30-day, 90-day, 365-day, lifetime)
Plausible Daily pageviews, visitors, visits
OpenVSX Total downloads, reviews, ratings
YouTube Views, likes, comments, subscribers (channel and per-video)

Which days are fetched

Every source counts its days in a time zone of its own: GitHub’s star history in US Pacific time, Plausible in each site’s time zone, the others in UTC. A day is fetched once it has ended in its time zone, plus an hour for the source to finish counting it, and never again. CRAN and PyPI publish late; they’re fetched through the last day they’ve published. So nothing is stored while it’s still in progress, and a day that wasn’t fetched is fetched by the next run.

Each target remembers how far it has been fetched in its project’s _watermark.json (_watermark-stars.json for the star history), and the next fetch continues from there. An explicit --start-date and --end-date override that.

install-ci schedules the nightly run an hour after the last of those days has ended, at half past: 09:30 UTC with GitHub’s star history, later with Plausible sites in the Americas.

Settings

[settings]
# Report what the gate would do (the default), or enforce it.
gate = "enforce"
# The day of the month from which the previous month is concatenated.
concatenate_on_day = 8
# Archive the responses of data that can't be fetched again (on by default).
archive = true
# Assigned to (users) or mentioned in (teams) the tracking issue.
owners = ["jeroenjanssens", "@posit-dev/devrel"]

# A Plausible site's time zone, for accounts without access to the Sites API.
[settings.timezones]
"example.com" = "America/New_York"

See Keeping the data right for the gate, the archive and the tracking issue.

Data dictionary

velocirepo export --data-dict writes a data dictionary of the export. Add what velocirepo can’t know about your data to velocirepo.toml:

[projects.shiny]
github = "rstudio/shiny"
# An old project id kept for its history: every target is also tracked by shiny-r.
duplicate_of = "shiny-r"

[projects.tidyverse]
cran = "tidyverse"
# What the project is, for the dictionary's glossary.
notes = "The tidyverse meta-package, not a rollup of all tidyverse packages."

[data_dict]
name = "acme-oss"
description = "Adoption and engagement of Acme's open source projects."

# The project that keeps a target that more than one project tracks.
[data_dict.keep.plausible]
"shiny.posit.co" = "shiny-python"

[[data_dict.notes]]
tables = ["metrics"]
source = "cran"
text = "The series misses 20 days since 2012."

See Data Dictionary for every key.

Next steps