Color to grayscale converter
Get the gray that keeps a color's perceived brightness: #3498db becomes #828282, a gray value of 130, because green counts most, red less and blue least. You also see each step of the arithmetic. Free in your browser.
- Free
- Runs in your browser
- No sign-up
- Your data stays on your device
Run — free
Worked example
- Source color as hex
- #3498db
- Value
- 130
- Input hex
- #3498db
- Input rgb
- 52, 152, 219
- Resistance (Ω)
- 52
A color to grayscale converter takes one opaque color—written as a hex code or as red, green, and blue channels—and maps it to a single neutral gray that preserves perceived brightness instead of averaging channels naively. Paste #e74c3c, rgb(52, 152, 219), or separate r, g, and b integers; the tool applies the classic luminosity weights zero point two nine nine red, zero point five eight seven green, and zero point one one four blue, rounds to an integer gray from zero through two hundred fifty-five, and returns the gray hex triple, the numeric value, a CSS rgb() string, and step-by-step arithmetic.
Why luminosity weighting beats a plain average
Human vision is not equally sensitive to red, green, and blue light. Green contributes most to perceived brightness, red less so, and blue least of all. That is why a pure blue #0000ff looks darker than a pure green #00ff00 even though both have a single channel maxed at two hundred fifty-five.
A naive average that adds the three channels and divides by three therefore under-represents how bright a green-heavy color feels and over-represents blue-heavy tones. Luminosity weighting corrects that imbalance with fixed coefficients drawn from the classic television luma model often called BT.601: gray Y equals zero point two nine nine times red plus zero point five eight seven times green plus zero point one one four times blue, then rounded to the nearest integer in zero through two hundred fifty-five.
The result is a single channel that, when written as #YY where each pair is the same hex byte, sits on the neutral axis of RGB space while keeping the same approximate brightness as the original hue. This landing is intentionally a single-color tool, not an image filter: you convert one design token, one CSS variable, or one palette swatch at a time and get an auditable gray hex and value back.
Classroom exercises and coding interviews often ask for this transform by hand; having a deterministic reference removes ambiguity about which weights were used, how rounding is applied, and whether three-digit hex shorthand was expanded before the multiply.
What you can do with it
Monochrome design tokens from brand hex
Designers paste brand hex codes and receive luminosity-weighted gray hex values for monochrome themes, print mockups, and disabled-state UI without opening an image editor.
CSS variable and canvas fill prep
Convert user-supplied colors from a picker into neutral rgb() and hex strings for grayscale previews, watermark layers, or print-friendly CSS variables.
FAQ
What formula does the color to grayscale converter use?
The gray hex repeats that byte three times as #YY.
Which color formats are accepted?
Hex #RGB or #RRGGBB (optional #), CSS rgb(r,g,b), bare r,g,b lists, or separate r, g, and b integer fields from 0–255. Alpha and named CSS colors are not accepted.
Is the color to grayscale converter free?
The browser tool is free and runs locally.
What gray does #3498db turn into?
It becomes #828282. The weighted sum is 0.299 × 52 + 0.587 × 152 + 0.114 × 219 = 129.738, which rounds to a gray value of 130, written as rgb(130, 130, 130).
Why not simply average red, green and blue?
Because the eye does not see the three as equally bright. Green adds most to perceived brightness and blue least, so a plain average makes green-heavy colors too dark and blue-heavy ones too light; that is why #0000ff looks darker than #00ff00.
Related tools
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, by email and from Telegram — and soon from our app too.
Call it from your stack
curl -X POST https://api.kit.forhosting.com/color/grayscale \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"color":"#3498db","hex":"valor-ejemplo"}'const res = await fetch("https://api.kit.forhosting.com/color/grayscale", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"color": "#3498db",
"hex": "valor-ejemplo"
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/color/grayscale",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"color": "#3498db",
"hex": "valor-ejemplo"
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/color/grayscale", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"color":"#3498db","hex":"valor-ejemplo"}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"color":"#3498db","hex":"valor-ejemplo"}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/color/grayscale", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"color": "#3498db",
"hex": "valor-ejemplo"
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "color.grayscale",
"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_channel | 255 |
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. |
Technical notes
Invalid colors—empty input, wrong hex length, non-hex characters, channels outside zero through two hundred fifty-five, or a missing field set—fail with a clear invalid_input error instead of inventing a swatch.
How to call the API and what comes back
Surrounding whitespace is trimmed, hex letters may be upper or lower case, and the hash is optional. Send a JSON body with either a color string or three separate channel fields. The color field accepts aliases hex, value, text, input, and code; valid examples include #3498db, 3498db, #abc, rgb(52, 152, 219), and the bare list 52, 152, 219. Alternatively provide r, g, and b (aliases red, green, blue) as integers from zero through two hundred fifty-five. On success the response returns input_hex and input_rgb for the resolved source, integer gray and aliases gray_value and value, gray_hex and hex as the six-digit neutral code, gray_rgb as a three-element array, css as rgb(g, g, g), formula and weights documenting the coefficients, luminosity as the pre-round weighted sum with fixed display precision, message as a short English summary, and steps as an ordered array of substitution lines for teaching or debugging. Failed validation—missing color and missing channels, empty string, wrong hex length, non-hex characters, a programming 0x prefix, channels outside range, or non-integer fractional channels—returns invalid_input and is never charged. Pricing is a flat $0.002 per successful request with unit item and zero marginal unit price.
Practical tips, limits, and related searches
Do not pass alpha forms such as #RRGGBBAA or rgba with a meaningful alpha you need preserved—this landing converts opaque RGB only, and unexpected lengths are rejected so you notice rather than silently dropping alpha. Named CSS colors like rebeccapurple are out of scope; resolve them to hex first with a name table, then call this converter. Prefer this capability when you already have one color and only need its luminosity gray hex and integer value; if your pipeline must still emit HSL or print CMYK, use a multi-format color converter for those spaces and this tool for the monochrome step. Prefer sending the exact token your design tool exported, including the hash if you have it; both hashed and bare hex work, and the response always normalizes the source to a lowercase six-digit input_hex so downstream diffs stay stable. Failed tasks that return invalid_input do not consume prepaid balance, which keeps exploratory scripts and form validation cheap while learners paste imperfect clipboard values.
Integration use cases
Unit tests for desaturation helpers
Generate known-good gray values from hex and RGB fixtures so theme engines and accessibility contrast checks assert stable luminosity math.
Technical questions
What is returned on success?
The integer gray value (also gray_value and value), gray_hex / hex, gray_rgb, a css rgb() string, the source input_hex and input_rgb, formula, weights, luminosity, message, and steps.
What happens on an invalid color value?
The API returns invalid_input with a message describing the problem (empty input, bad hex, out-of-range channels, and so on). Failed validation is not charged.