Library / SDK
18F/analytics.usa.gov avatar
18F/analytics.usa.gov

analytics.usa.gov publishes how federal web traffic actually behaves

The US federal government's web traffic.

786 stars260 forksJavaScriptNOASSERTION

At a glance

What is it?
analytics.usa.gov is the public dashboard for the Digital Analytics Program, which collects and publishes web analytics from thousands of federal websites under a White House mandate. The site is a Jekyll build with React and d3 charts bundled by webpack, and the interesting engineering is in the deployment pipeline that turns three branches into three environments automatically.
Who is it for?
Adopt this repository if you are building a public statistics dashboard and want to see how a federal team handles branch-based deployment, accessibility checking and historical data downloads rather than reinventing those parts. Skip it if you need a modern component library or a data pipeline, because the collection side lives in the separate analytics-reporter and analytics-reporter-api repositories.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository last received commits 17 days ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The data comes from a mandate, not from a scraper

analytics.usa.gov is a product of the Digital Analytics Program, which collects and publishes web analytics from thousands of public-facing US federal government websites. The basis for that collection is the Delivering a Digital-First Public Experience requirement, built in support of the 21st Century Integrated Digital Experience Act.

That framing matters for anyone considering reusing the code. This is not a project that instrumented a few sites and generalised; the programme has a policy basis, which is why the data exists and why the site can present it as official statistics.

The repository itself is the front end. The documentation states plainly that this is the main repository for analytics.usa.gov, and that additional repositories exist for the data collection and the API: the analytics-reporter and analytics-reporter-api repositories. So the split is clear. This tree holds the dashboard. The scraping, the API and the historical downloads live elsewhere.

The homepage is analytics.usa.gov and the default branch is develop, with master, staging and develop forming the deployment ladder described below.

The licence is the first thing to note for reuse. It is not one of the standard identifiers: the licence field reads Other, a custom licence GitHub cannot classify, and points to the LICENSE file. The package file is equally clear, with the licence field set to SEE LICENSE IN License.md. Anyone planning to reuse the code should read that file rather than assume MIT or Apache terms.

Jekyll pages with React and d3 mounted onto them

The component stack is described directly in the documentation.

The app uses Jekyll to build the site and Sass for CSS. The JavaScript is a webpacked aggregation of several different modules, leveraging React and d3 for the visualizations.

The module layout explains the slightly unusual arrangement. The Index module is the entry point for the webpack bundler and pulls in all React component JS to make it available for rendering. The js/components directory holds the top level React component definitions, and the components which render charts contain the d3 logic inside them.

The reason d3 lives inside the components rather than in a separate visualisation library is stated in the documentation. This is not a full React app, because many pages are generated statically by Jekyll. So index.js files within some component directories run createRoot from the react-dom library to inject React components at certain elements. The pattern is a static page with React islands attached, which is a pragmatic fit for a content site that happens to need charts.

Two other pieces of the module list are worth knowing. lib/chart_helpers holds d3 helper functions shared between multiple charts, so common scales and formatting live in one place. And lib/touchpoints.js is third party code from the Touchpoints project, included in this repository rather than loaded remotely, with the stated reason being to avoid Content Security Policy problems from remote-hosted scripts.

The repository root shows the rest of the front end: _data/, _includes/, _layouts/, _plugins/, css/, sass/, images/, fonts/, js/, spec/ and a webpack.config.js at the top level alongside a gulpfile.js and a Makefile.

Local development needs Ruby and Node before anything else

The prerequisites are pinned, which is a good sign for a project that has been running in CI for years. The documented requirements are Ruby 3.3.6 and NodeJS 22.x.x, and the repository carries a .ruby-version and a .nvmrc file to match.

After installing Ruby and Node, the library dependencies go in with two commands:

bash
# Install dependencies
bundle install
npm install

Bundler handles the Ruby side, which is Jekyll and its plugins, and npm handles the JavaScript side, which is webpack, React, d3 and the test and lint tooling.

The site is then built and served locally with a single command that watches for changes:

bash
# Compile and serve the full site locally, watching for changes.
npm start

That command is a parallel run of three steps, which the package file spells out: build:local, watch:local and serve:local. The build runs gulp to build assets and then webpack in development mode with watch, the watch task runs gulp watch, and serve:local runs make local. The Makefile shows what that last one does:

code
local:
	bundle exec jekyll serve --watch --config=_config.yml,_development.yml

So the local server is Jekyll's own, with the development configuration file layered on top of the main one. The site is served at http://localhost:4000 and reloads when source files change.

Linters, unit tests and accessibility checks are separate commands

The project treats code quality as three separate checks rather than one, and each has its own npm script.

JavaScript is linted with:

bash
# JavaScript
npm run lint:js

Styles are checked with stylelint over the Sass sources:

bash
# SCSS
npm run lint:styles

HTML is checked with prettier in check mode:

bash
# HTML
npm run lint:html

The documentation notes that you can add `:fix` to any of these and the linter will attempt to fix common issues automatically. The package file carries matching fix variants, lint:js:fix, lint:styles:fix and lint:html:fix. These checks are also enforced in CI where possible.

Unit tests run with jest:

bash
npm test

and the repository carries jest.config.js and jest_setup.js alongside an nyc.config.js for coverage.

Accessibility gets the most attention of any check, with two independent tools. With the site running locally, you can test with pa11y or with Axe:

bash
# Run pa11y checks
npm run accessibility:pa11y

# Run axe checks
npm run accessibility:axe

The axe script points at six specific pages of the local site: the root, data, about, definitions, historical-data-download and 404. There is a separate CI variant of the same command that supplies a chromedriver path and an exit flag, and a .pa11yci configuration file for pa11y-ci.

One more convenience is the git hooks. The hooks/ directory contains hooks that check out current npm packages on branch change events and run the linters and unit tests on pre-commit, installed with `npm run install-git-hooks`.

Local data comes over HTTP with CORS, and that is the fiddly part

The development settings assume data is available at `/ga4-data`, and the path can be changed in `_development.yml`. The ga4-data/ directory is present at the repository root, so a checked-out tree can start with whatever sample data is committed.

Working from real live data is where the setup gets specific. If you are working off local data from the analytics-reporter project, you need the data available over HTTP and through CORS.

The recommended tool is the Node module serve, installed globally:

bash
npm install -g serve

Data is then generated into a directory:

code
analytics --output [dir]

and serve is run from that output directory:

bash
serve --cors

The result is that the data is available at http://localhost:4000 over CORS with no path prefix, so device data lands at http://localhost:4000/devices.json.

This is a small but telling detail. The site is statically generated but fetches its data at runtime from a JSON endpoint, which means the development setup has to solve cross-origin requests, and the project solves it with a local static server rather than by weakening the security model.

For adding agencies, the process is a data file edit rather than a code change. You ensure data is being collected for the agency's Google Analytics ID, note the url path for the data collection path, and create a new json object in the `/_data/agencies.json` file, where the `slug` attribute is the url path and the `name` attribute is the display name.

Three branches, three environments, one CI pipeline

The deployment model is the cleanest part of the documentation to read.

Production, staging and dev applications are deployed via CI automatically. Any commits to the `master` branch are deployed to production after passing automated tests in CI. Commits to the `staging` branch go to the staging environment, and commits to the `develop` branch go to the development environment.

The environments line up as follows: production on master at https://analytics.usa.gov, staging on staging at https://analytics-staging.app.cloud.gov, and development on develop at https://analytics-develop.app.cloud.gov.

Manual deployment should not be necessary, but the documentation gives the commands anyway for the case where the Cloud Foundry CLI is installed. To deploy to analytics.usa.gov after building the site with the details in `_config.yml`:

bash
make deploy_production

and for analytics-staging.app.cloud.gov, after building with `_config.yml` and `_staging.yml`:

bash
make deploy_staging

The Makefile also shows the production build step itself, which runs the gulp and webpack production build and then the Jekyll build. The deployment target is Cloud Foundry, and the repository carries a buildpack.yml, an nginx.conf, newrelic.yml and a mime.types file.

One configuration detail deserves attention if you touch the historical data page. The historical data downloads page makes API calls, proxied through the site's NGINX server, to the DAP API handled by the analytics-reporter-api application, and those calls include an api.data.gov API key. The key is provided as configuration by CI. So a private credential sits in the proxy path, which is why the NGINX layer is in the tree at all.

The repository also carries a SECURITY.md, a system-security-plan.yml, a compliance/ directory, a CONTRIBUTING.md, a docs/ folder that includes the development and deployment process document, and a manifest.yml.

On maintenance, the last push was on 2026-10-06, while the tagged releases are v2.4.0 from 2025-02-25, v2.3.0 from 2025-01-15 and 2.1.0 from 2024-11-14. The release names carry their month and year, so the project versioned by release window rather than by a plain semver sequence, and the site itself is expected to change as the programme collects more data.

Editorial conclusion

Adopt this repository if you are building a public statistics dashboard and want to see how a federal team handles branch-based deployment, accessibility checking and historical data downloads rather than reinventing those parts. Skip it if you need a modern component library or a data pipeline, because the collection side lives in the separate analytics-reporter and analytics-reporter-api repositories. Verify first that your data source can serve JSON over HTTP with CORS, since the local development path depends on it, and check the licence in License.md, which GitHub cannot classify.

Frequently asked questions

What is analytics.usa.gov and where does the data come from?

It is the public dashboard of the Digital Analytics Program, which collects and publishes web analytics from thousands of public-facing US federal websites per the Delivering a Digital-First Public Experience requirement built in support of the IDEA act. The collection and API live in the separate analytics-reporter and analytics-reporter-api repositories.

How do I run analytics.usa.gov locally?

Install Ruby 3.3.6 and NodeJS 22.x.x, then run `bundle install` and `npm install`. Running `npm start` builds the assets and serves the site at http://localhost:4000 with reload on change.

How do I deploy changes to analytics.usa.gov?

You normally do not deploy manually. Commits to master go to production, staging goes to the staging environment and develop to development, all after passing CI tests. The manual path uses the Cloud Foundry CLI with `make deploy_production` or `make deploy_staging`.

What licence does analytics.usa.gov use?

A custom licence that GitHub cannot classify. The licence field lists it as Other, and the package file points to SEE LICENSE IN License.md, so the terms need to be read in that file before reuse.

Official sources

  1. 18F/analytics.usa.gov on GitHub
  2. Issues
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/18f-analytics-usa-gov.svg)](https://hysenlabs.com/projects/18f-analytics-usa-gov)

Was this useful?