Color contrast checker
A color pair can look perfectly readable on one display and still fail the contrast required for accessible text. Enter the foreground and background colors to calculate their exact WCAG contrast ratio and see separate AA and AAA decisions for normal and large text.
Run — free
Runs in your browser. Free, unlimited — your data never leaves this page.
From two swatches to an objective answer
Visual judgment is a poor contrast meter. Screen brightness, font weight, ambient light and even the neighboring colors can make the same pair feel clearer or weaker than it really is. This checker converts both colors into sRGB, calculates their relative luminance and compares the lighter value with the darker one using the WCAG formula. The result is a ratio rather than a vague label, followed by four practical decisions: AA and AAA for normal text, and AA and AAA for large text. That separation matters because a headline may pass where smaller body copy does not.
Accepted color notation and predictable normalization
Paste common values straight from a stylesheet or design token: three- or six-digit HEX, an rgb() triplet, or an hsl() color with percentage saturation and lightness. Each input is returned as normalized six-digit HEX and RGB, which makes the calculation easy to reproduce in a design system or test suite. Alpha channels are intentionally excluded. A translucent foreground cannot be assessed honestly without knowing every layer beneath it, so accepting an incomplete composition would produce a confident but potentially false ratio. Flatten transparent colors against their final background before checking them here.
How to use the result in real interface work
Treat the matrix as a design constraint, not as a promise that the whole page is accessible. A passing normal-text result answers only the relationship between these two solid colors; it does not inspect font size, weight, hover states, gradients, images, focus indicators or the semantics of the page. Check each meaningful state separately, including disabled controls only when their content still needs to be read. Because the browser tool performs the calculation locally, it is useful during rapid design review. For automated token checks or CI, send the same two fields to the API and receive the identical structured object.
What you can do with it
Design-token review
Test text and surface tokens before releasing a palette, with separate decisions for body copy and display text.
Component quality assurance
Verify default, hover, selected and error states without relying on a reviewer’s monitor or visual impression.
Automated accessibility checks
Call the API from CI to reject a color pair that falls below the WCAG threshold required by the product.
FAQ
Which color formats can I enter?
You can use three- or six-digit HEX, rgb() with three channels, or hsl() with saturation and lightness percentages. Alpha and named colors are not accepted.
What do AA and AAA mean in the result?
They are WCAG conformance thresholds. The checker reports them separately for normal and large text because the required contrast differs by text size and weight.
Is the color contrast checker free?
The tool on this page runs free inside your desktop or mobile browser. The API costs $0.002 per successful request and uses your prepaid KIT balance.
Does the native mobile app run the free browser widget?
No. The native app invokes the API and shows the price for that task in the app. Open this page in a mobile browser when you want the local browser version.
Can this result prove that my page is WCAG compliant?
No. It verifies one solid foreground and background pair. A full review must also cover typography, interface states, images, keyboard access, labels and other accessibility requirements.
Why are transparent colors rejected?
Their visible color depends on the layers underneath. Flatten the color against its final background first, then check the resulting opaque pair.
For developers — API access
Everything on this page is available programmatically. This section is for teams who want to wire it into their own systems; everyone else can just use the tool above.
API endpoint
Prefer to automate it? One authenticated POST creates the task; the result comes back by webhook or a signed link. The same capability also runs here on the web, and soon from our app, email and Telegram.
Call it from your stack
curl -X POST https://api.kit.forhosting.com/verify/color-contrast \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"items":["valor-1","valor-2"]}'const res = await fetch("https://api.kit.forhosting.com/verify/color-contrast", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"items": [
"valor-1",
"valor-2"
]
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/verify/color-contrast",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"items": [
"valor-1",
"valor-2"
]
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/verify/color-contrast", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"items":["valor-1","valor-2"]}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"items":["valor-1","valor-2"]}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/verify/color-contrast", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"items": [
"valor-1",
"valor-2"
]
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "verify.color_contrast",
"status": "queued",
"_links": {
"result": "/tasks/tsk_…/result"
}
}The API is asynchronous: the call returns a task_id immediately and the result arrives by webhook. Polling is capped at 1 req/s per task.
Pricing
Published price — no tokens, no invented credits. A failed task is never charged.
Limits
max_color_chars | 100 |
Errors
| HTTP | Code | Meaning |
|---|---|---|
401 | unauthorized | Missing or invalid API key. |
402 | insufficient_balance | Your balance doesn't cover the task price. |
404 | unknown_type | That task type doesn't exist. |
429 | rate_limited | Too many requests. Use the webhook instead of polling. |