Black-and-white an image
Converting an image to grayscale sounds trivial until you need to do it consistently across thousands of files with different color profiles and bit depths. This endpoint takes any supported image and returns a clean black-and-white version, luminance-weighted rather than a flat average, so the result actually looks right instead of muddy.
Run it online
Run this on our servers with your account. Free tools run in your browser; this one bills your KIT balance per the price above.
Why grayscale still matters
Print shops still ask for it, legal and medical document pipelines still require it, e-commerce catalogs use it to preview product variants, and plenty of design systems fall back to it for placeholder or disabled states. Anyone shipping a document pipeline, a print workflow, or a photo archive eventually needs a dependable way to strip color without babysitting the job by hand.
How the conversion actually works
The endpoint reads the source pixels and applies a luminance-weighted conversion, giving green more visual weight than blue and red the way the human eye perceives brightness. That single choice is why naive grayscale filters look flat while this one preserves contrast and detail in skin tones, skies and shadows alike.
What to send and what comes back
Send the image by URL or upload, call POST /image/grayscale, and you get a task_id immediately since every job runs asynchronously. When the conversion finishes you receive the file through a signed webhook, which we recommend for pipelines, or through a signed link that stays valid for 24 hours if you'd rather poll or hand it to a person.
A short note on the format's history
Grayscale as a deliberate output format predates color photography by decades and remained the default for newsprint and legal scanning long after color became affordable, simply because it compresses smaller and reproduces more reliably on cheap hardware. That legacy is exactly why grayscale conversion is still a first-class need in modern document and print automation rather than a stylistic afterthought.
Fitting it into a pipeline
Because every call is billed only on success, three retries happen automatically before you ever see a failed, charged request, which means you can wire this into a batch job or a document ingestion pipeline without writing your own retry logic. There is no free tier and no trial queue slowing anyone down; prepaid balance mean your job starts immediately, and a 402 response tells you plainly if it doesn't, instead of silently queuing. That predictability is what makes the endpoint safe to schedule as a recurring step rather than a manual chore someone has to remember.
What you can do with it
Print-ready document pipelines
Legal and government document scanners convert incoming color scans to grayscale automatically before archiving, cutting file size while meeting print and compliance requirements.
Product photo previews
E-commerce platforms generate a grayscale preview of each product photo to signal out-of-stock or discontinued variants without re-shooting anything.
Design system placeholders
UI teams batch-convert marketing imagery into grayscale placeholders for disabled or loading states so the visual language stays consistent across the product.
Photo archive normalization
Digital archives standardize scanned historical photographs to grayscale for consistent display alongside originals that were never in color.
FAQ
What does the grayscale image API actually do?
It takes any supported image and returns a luminance-weighted black-and-white version through the POST /image/grayscale endpoint, delivered async via webhook or a 24-hour signed link.
Is there a free tier for the grayscale image API?
There's no free tier — free tiers get abused and slow everyone down. Access runs on a prepaid ForHosting KIT balance: top up from $10.00 (it never expires) and each request is charged at its published price, so a call with no balance returns HTTP 402. No subscription, no tokens, no invented credits, and a failed task is never charged.
How much does it cost to convert an image to grayscale?
Each call is $0.002 per request plus $0.005 per image processed, billed only when the conversion succeeds.
Which image formats are supported?
The endpoint accepts the standard raster formats used across our image tools; check the current endpoint reference for the exact list before sending unusual color profiles.
Do I get charged if the conversion fails?
No. A failed task is never charged. The system retries automatically up to three times before returning a clear error, at no cost to you.
Can I process images in bulk?
Yes, submit one call per image and they run independently and asynchronously, so you can fan out large batches without waiting on any single job.
How is grayscale different from a flat black-and-white average?
This endpoint uses luminance weighting, which reflects how the human eye perceives brightness, so contrast and detail hold up far better than a simple RGB average.
How long do I have to download the result?
The signed result link stays valid for 24 hours; after that, and after our standard retention window, the file is deleted and never used for training.
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/image/grayscale \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"image":"https://ejemplo.com/imagen.jpg"}'const res = await fetch("https://api.kit.forhosting.com/image/grayscale", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"image": "https://ejemplo.com/imagen.jpg"
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/image/grayscale",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"image": "https://ejemplo.com/imagen.jpg"
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/image/grayscale", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"image":"https://ejemplo.com/imagen.jpg"}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"image":"https://ejemplo.com/imagen.jpg"}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/image/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
{
"image": "https://ejemplo.com/imagen.jpg"
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "image.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_mb | 15 |
max_megapixels | 12 |
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. |