Integration · Setup
Contrast in CI Fail the pull request, and say what to change
A small script sends each of your color pairs to the API, fails the job when one falls short, and names the nearest text color that passes. The output on this page is the script’s own, from running it against the API’s server.
- Needs
- An API key on the Specialist plan; Node.js 18 or later
- Cost
- One credit a pair, three for a pair that fails
- Checked
Before you start
What you need
- An API key from your dashboard, on the Specialist plan. Apprentice and Artisan plans have no API access.
- A repository on GitHub, or any CI that runs Node.js 18 or later. The script was run on Node.js 24.11.0.
- Your color pairs: which text sits on which background, and the ratio it needs.
Setup
Step by step
-
Write your pairs
One entry for each pair that must stay readable: text on its background at 4.5:1, large text and the edges of controls and icons at 3:1. Name each pair the way your team does.
[ { "name": "Body text", "fg": "#1F2937", "bg": "#FFFFFF", "min": 4.5 }, { "name": "Muted text", "fg": "#9CA3AF", "bg": "#FFFFFF", "min": 4.5 }, { "name": "Button label", "fg": "#FFFFFF", "bg": "#4338CA", "min": 4.5 }, { "name": "Input border", "fg": "#6B7280", "bg": "#FFFFFF", "min": 3 } ] -
Add the script
Put
check-contrast.mjsat the root of the repository. It needs nothing but Node.js: no packages and no lockfile.# macOS and Linux AURIC_API_KEY="aa_your_key" node check-contrast.mjs contrast-pairs.json # Windows PowerShell $env:AURIC_API_KEY = "aa_your_key"; node check-contrast.mjs contrast-pairs.json -
Store the key as a secret
In the repository’s settings, add a secret named
AURIC_API_KEYholding your key. The workflow passes it in, and the script never prints it. -
Add the workflow
Save it as
.github/workflows/contrast.yml. It runs on every pull request, and from the Actions tab whenever you ask.# Check color contrast on every pull request. # From https://auricartisan.com/integrations/contrast-ci/ - CC0 1.0. # Put this file in .github/workflows/, check-contrast.mjs and contrast-pairs.json # at the root of the repository, and an API key in the repository secret AURIC_API_KEY. name: Contrast on: pull_request: workflow_dispatch: permissions: contents: read jobs: contrast: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - uses: actions/setup-node@v6 with: node-version: 24 - name: Check color contrast run: node check-contrast.mjs contrast-pairs.json env: AURIC_API_KEY: ${{ secrets.AURIC_API_KEY }}
A real run
A failure, and its fix
The script’s output on the sample pairs, from running it against the API’s own server. One pair fails, so the job fails, and the line says what to change.
PASS Body text: #1F2937 on #FFFFFF is 14.67:1, needs 4.5:1
FAIL Muted text: #9CA3AF on #FFFFFF is 2.53:1, needs 4.5:1 - nearest passing text color #6D7787 (4.52:1)
PASS Button label: #FFFFFF on #4338CA is 7.90:1, needs 4.5:1
PASS Input border: #6B7280 on #FFFFFF is 4.83:1, needs 3:1
3 of 4 pairs pass.
Exit code 1: a pair fails
::error title=Contrast - Muted text::#9CA3AF on #FFFFFF is 2.53:1, needs 4.5:1. Try the nearest passing text color #6D7787 (4.52:1).
PASS Body text: #1F2937 on #FFFFFF is 14.67:1, needs 4.5:1
PASS Muted text: #6D7787 on #FFFFFF is 4.52:1, needs 4.5:1
PASS Button label: #FFFFFF on #4338CA is 7.90:1, needs 4.5:1
PASS Input border: #6B7280 on #FFFFFF is 4.83:1, needs 3:1
4 of 4 pairs pass.
Exit code 0: every pair passes
check-contrast: set AURIC_API_KEY to an API key (a repository secret on CI)
Exit code 2: the check could not run
What the exit codes mean
| Code | Meaning |
|---|---|
| 0 | Every pair passes. The job is green. |
| 1 | A pair is below its ratio. The job fails, and each failing line names the nearest passing text color. |
| 2 | The check could not run: no key, a pairs file it cannot read, or an answer from the API that is not a result. Nothing was judged. |
Remediation
Fixing a failure
-
Change the token, not each use
The suggestion keeps the hue and moves the lightness. Put it in the token the pair comes from, so every use follows, then run the check again.
-
If the suggestion is wrong for the brand, move the background
A ratio has two sides. A darker or lighter surface can bring the pair up without touching the brand color.
-
When no text color passes
On a mid-tone background neither black nor white may reach the ratio; the line then says to change the background.
FAIL Small print, AAA: #FFFFFF on #6B7280 is 4.83:1, needs 7:1 - no text color on this background reaches it; change the background ::error title=Contrast - Small print, AAA::#FFFFFF on #6B7280 is 4.83:1, needs 7:1. No text color on this background reaches it: change the background. 0 of 1 pairs pass.
Limits
What it does not do
- It checks the pairs you list, not your pages: a pair you leave out is not checked. Keep the list next to your tokens, and run an audit on the pages too.
- The ratio is WCAG 2’s. The API measures APCA too; this script does not use it.
- Each run spends credits from your plan, which is why the workflow runs on pull requests and not on every push.
- The workflow file was parsed as YAML, and the script was run against the API’s server; neither was run on GitHub for this page.
Privacy and access
What it sends
- The colors in your pairs file, and nothing else, go to the API with your key.
- The key stays in your CI’s secret store; the script never prints it.
Go further
The full reference
- The REST API guide: keys, requests and answers
- Credits and rate limits, in the reference
- How to fix a contrast failure
- Check one pair by hand in the contrast checker
- Accessible color and WCAG contrast, explained
Other integrations
- Browser extensionCheck and fix contrast on the page in front of you.
- VS CodeUnderline low contrast in your stylesheets and fix it in place.
- REST APIConvert colors and check pairs from a server or a script.
- Design tokensExport one token system to Tailwind, CSS or Figma.
- Contrast embedPut a contrast checker on your own page.
- Tailwind themeStart a Tailwind v4 project with accessible components.
- React tokensTheme a React app from the token export.
- Figma variablesTurn Figma variables into CSS tokens.
Checked against
Where these facts come from
Versions, requirements and examples on this page were checked on . The script was run with Node.js 24.11.0 against the API’s own server, started in local open mode: on the sample pairs it exited with 1, with the suggested color applied with 0, with no key with 2, and on a pair no text color can fix with 1. The output shown is from those runs. The workflow file was parsed with the yaml package 2.9.1; it was not run on GitHub.
- GitHub Docs: Workflow syntax for GitHub Actionsdocs.github.com
- GitHub Docs: Using secrets in GitHub Actionsdocs.github.com
- GitHub Docs: Workflow commands, setting an error messagedocs.github.com
- actions/setup-nodegithub.com
- Auric Artisan API: endpoint listapi.auricartisan.com
- Understanding WCAG 2.2: Contrast (Minimum)www.w3.org
Found a mistake? Write to us and we will correct it.