Free colour palette from an image
Drop an image and get its main colours as hex and RGB with the share of the picture each one covers, the average colour and a 16 pixel placeholder for lazy loading. The form calls the same free API your code can call: one POST, no API key and no account.
curl -s -X POST https://aisenseapi.com/services/v1/image_colors \
-F "file=@photo.jpg" \
-F "count=6"
{
"storage_id": "c6c032dc-1398-4feb-9627-096cf0e7c915",
"storage_url": "https://aisenseapi.com/services/v1/storage/c6c032dc-1398-4feb-9627-096cf0e7c915",
"sha256_hash": "486fb024009f465197227d0151dabb14c92d7b4c6d75b56d4c4da6a124d80077",
"bytes": 2461,
"expire_timestamp": 1790778560,
"expire_datetime": "2026-09-30T14:29:20+00:00",
"content_type": "application/json",
"filename": "colors.json",
"operation": "image_colors",
"average": "#4A5764",
"dominant": "#3E3641",
"count": 6
}Try it in the browser
This form posts your image to the same endpoint and shows the stored result. The image is sent to aisenseapi.com, and the result is kept for 24 hours at a link that anyone with the link can open.
How the colours are found
- The image is made small first, at most 128 pixels on its longest side, so a large photo is as quick as a small one.
- ImageMagick reduces it to the number of colours you ask for, 2 to 16 and 8 when you ask for none, without dithering, and counts the pixels of each. A colour's
shareis its part of the visible pixels. An image with fewer colours gives fewer. - Transparent pixels are left out and counted as
transparent_share, so a logo on a transparent background gives the colours of the logo. - The average is the mean colour of the visible pixels of the reduced image.
- The placeholder is the image at most 16 pixels on its longest side, as a PNG data URI, to show while the real image loads.
- The image is turned upright first, and a CMYK JPEG is converted to RGB.
The API
POST https://aisenseapi.com/services/v1/image_colors with multipart/form-data.
| Field | Required | Meaning |
|---|---|---|
file | yes | The image: JPEG, PNG or WebP. |
count | no | How many colours, 2 to 16. 8 when left out. |
The palette is stored as colors.json, and the answer holds the Storage fields and the main points:
| Field | Meaning |
|---|---|
storage_id, storage_url | Where the result is. A GET on the URL returns it. |
sha256_hash, bytes | The digest and size of the stored result. |
expire_timestamp, expire_datetime | When the result is removed, 24 hours after it was stored. |
content_type, filename | application/json and colors.json. |
operation | image_colors. |
average, dominant | The average colour and the colour with the largest share, as hex. |
count | How many colours the palette holds. |
The example at the top of the page comes from a test run with a test image of 1600 x 1200 pixels and count=6. The stored palette, with the placeholder cut short here:
{
"width": 1600,
"height": 1200,
"colors": [
{
"hex": "#3E3641",
"rgb": [
62,
54,
65
],
"share": 0.3922
},
{
"hex": "#59595B",
"rgb": [
89,
89,
91
],
"share": 0.2238
},
{
"hex": "#355F9A",
"rgb": [
53,
95,
154
],
"share": 0.1389
},
{
"hex": "#409DC4",
"rgb": [
64,
157,
196
],
"share": 0.0978
},
{
"hex": "#479863",
"rgb": [
71,
152,
99
],
"share": 0.0777
},
{
"hex": "#95565B",
"rgb": [
149,
86,
91
],
"share": 0.0696
}
],
"average": {
"hex": "#4A5764",
"rgb": [
74,
87,
100
]
},
"transparent_share": 0.0,
"placeholder": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB..."
}
Anyone with the link can read the palette until it expires. Stored results count against the Storage budget of 80 MB per IP address per day.
Limits
- The upload is a JPEG, PNG or WebP of at most 10 MB and 25 megapixels.
- One request may take at most 45 seconds.
- At most two images are worked on at a time, together with the image converter and image compression. A third waits up to ten seconds and is then answered 503 with
Retry-After.
Errors
A refused request stores nothing and answers with error. The endpoint's own refusals also carry fix, a sentence saying what to send instead.
| Status | When |
|---|---|
400 | A field is unknown or out of range, the upload is not one whole file, or ImageMagick cannot read the image. |
405 | The method is not POST. |
413 | The upload, its number of pixels or the result is over a limit. |
415 | The body is not multipart/form-data, or the file is not a JPEG, PNG or WebP. |
429 | More than 5000 requests from one IP address in 24 hours, or the day's Storage budget is used up. |
503 | Two images are being worked on already, the work took more than 45 seconds, or the service cannot do it right now. |
Questions
Is the colour palette API free?
Yes. No API key, no account and no sign up. The limit is 5000 requests per IP address per 24 hours, and stored results count against the Storage budget of 80 MB per IP address per day.
How many colours can I get?
2 to 16, and 8 when you do not say. An image with fewer colours gives fewer.
What happens to transparent pixels?
They are left out of the palette and the average, and transparent_share says how much of the image they cover.
Can I use the placeholder in an img tag?
Yes. It is a PNG data URI, so it works as the src of an img element or as a CSS background, with no extra request.
Related tools
- Image converter, which also reads HEIC, and image compression
- Image metadata viewer and EXIF remover
- Colour palette and favicon generator
- JSON to CSV, CSV to JSON and table matching
- JSON formatter and JSON validator
- File uploader and the Temporary Storage API, where every result is kept for 24 hours