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 initvelocirepo 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:
- Environment variables — export them in your shell (e.g.,
export GITHUB_TOKEN=ghp_...) .envfile — place a.envfile next to yourvelocirepo.toml; variables are loaded automatically- GitHub Actions secrets — when using
velocirepo install-cior 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 |
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.