OKLCH to hex converter
This OKLCH to hex converter turns a CSS-style OKLCH color into a six-digit sRGB hexadecimal value.
Run — free
It follows an explicit numerical path from cylindrical OKLCH coordinates through OKLab and linear RGB, then clamps channels that fall outside the displayable sRGB gamut. The result is deterministic, easy to automate, and accompanied by RGB and OKLab values so you can inspect exactly what was converted instead of treating the final hex code as a black box.
Enter a valid OKLCH color
Provide the color using CSS functional notation, such as oklch(62.8% 0.258 29.23). Lightness may be written as a percentage from 0% through 100%, or as a unitless value from 0 through 1. Chroma must be zero or positive. Hue is interpreted as degrees when it has no suffix, while the standard deg, grad, rad, and turn suffixes are also accepted. Hue can be outside the usual 0-to-360 range because it is normalized to the equivalent angle. The converter deliberately requires all three coordinates and does not accept alpha, the CSS none keyword, commas, hex input, or another color function. Those rules keep the contract focused on producing a six-digit opaque hex color and make malformed data fail clearly rather than being guessed into a plausible-looking result. Every numeric component must be finite; values such as Infinity and NaN are rejected before conversion begins. This strict input boundary is useful in build tools and data pipelines, where silently accepting an unintended format can spread an incorrect brand color through many generated assets.
Understand the conversion path
OKLCH describes a color with perceptual lightness, chroma, and hue. The converter first normalizes the hue and resolves the cylindrical coordinates into the a and b axes of OKLab with cosine and sine. It then applies the published OKLab transform to obtain linear sRGB channels. Those linear channels are passed through the standard sRGB transfer curve and quantized to integer red, green, and blue values from 0 through 255. Each byte becomes exactly two hexadecimal characters, so the primary result always has the form #RRGGBB. The response also includes the resolved OKLab coordinates and integer RGB channels. These intermediate values make debugging easier when a design application and a code pipeline appear to disagree. Floating-point intermediate values are rounded only for the reported OKLab object; the full internal precision is retained until the final RGB bytes are calculated. The algorithm uses no network service, random source, current time, locale formatting, or mutable state, so identical input produces identical JSON in the API and browser implementation.
Handle colors outside sRGB
OKLCH can describe colors that ordinary sRGB screens and six-digit hex notation cannot represent. When any converted linear RGB channel is below zero or above one, this converter clips that channel to the nearest boundary before applying the sRGB transfer curve. The response sets clamped to true whenever this happens. Clipping is predictable and fast, but it is not a perceptual gamut-mapping strategy: a very vivid input can lose nuance, change apparent hue, or collapse onto a fully saturated channel. Treat the flag as a signal to review the color, especially for brand palettes, accessibility tokens, and gradients where relationships between neighboring colors matter. If clamped is false, all channels were already inside sRGB before encoding. If it is true and visual fidelity is important, consider reducing chroma in the source OKLCH value and converting again until the color fits. This explicit behavior avoids invalid channel math and guarantees a usable six-digit output while remaining honest about the compromise. The conversion preserves no alpha channel because six-digit hex represents an opaque color; use a separate workflow when transparency is part of the intended result.
What you can do with it
Export design tokens
Convert perceptual OKLCH palette values into stable hex strings for systems that only accept six-digit sRGB colors.
Validate a color pipeline
Inspect RGB, OKLab, and the gamut-clamping flag when comparing output from design and development tools.
Generate compatible CSS
Create a deterministic hex fallback for an OKLCH color used in stylesheets, emails, templates, or legacy clients.
FAQ
What does the conversion cost?
It runs free in the browser on this page, or costs $0.002 for each API request.
Why does the output say clamped?
At least one calculated linear sRGB channel was outside the displayable range and was clipped to zero or one before encoding.
Does the converter support alpha transparency?
No. The target is a six-digit opaque hex string, so OKLCH input with an alpha component is rejected.
Which hue units can I use?
You may omit the unit for degrees or explicitly use deg, grad, rad, or turn. Angles are normalized to an equivalent value from zero up to 360 degrees.
Why can another converter produce a different hex value?
Tools can use different matrices, rounding rules, or gamut-mapping methods. This converter uses a fixed OKLab-to-sRGB transform, channel clipping, the sRGB transfer curve, and nearest-byte rounding.
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/oklch-hex \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"text":"oklch(62.8% 0.258 29.23)"}'const res = await fetch("https://api.kit.forhosting.com/color/oklch-hex", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"text": "oklch(62.8% 0.258 29.23)"
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/color/oklch-hex",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"text": "oklch(62.8% 0.258 29.23)"
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/color/oklch-hex", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"text":"oklch(62.8% 0.258 29.23)"}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"text":"oklch(62.8% 0.258 29.23)"}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/color/oklch-hex", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"text": "oklch(62.8% 0.258 29.23)"
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "color.oklch_hex",
"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.
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. |