# Color Palette Extractor: Dominant Colors from Images & Websites (`data-done-right/color-palette-extractor`) Actor

Extract a color palette from image URLs (JPG, PNG, WebP, GIF) with k-means or median cut, or read the colors a website's CSS uses. Hex, RGB, share, nearest color name, WCAG contrast and CSS/Tailwind snippets per item. Static fetch only, no JavaScript rendering.

- **URL**: https://apify.com/data-done-right/color-palette-extractor.md
- **Developed by:** [Data Done Right](https://apify.com/data-done-right) (community)
- **Categories:** Developer tools, Automation, Other
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.40 / 1,000 palette extracteds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Color Palette Extractor: Dominant Colors from Images & Websites

This **color palette extractor** pulls the **dominant colors** out of image URLs (JPG, PNG, WebP, GIF) with k-means or median cut, and can also read the colors a **website's CSS** declares. Every item gets its colors as hex, RGB and HSL, each color's share, the nearest CSS color name, WCAG contrast numbers, and ready-to-paste CSS variables and Tailwind colors.

> **What it does not do.** It does **not run JavaScript or a browser**: for websites it reads the static HTML, inline styles and up to 6 linked stylesheets, so colors that scripts or CSS-in-JS create at run time are missed (the row says so when nothing is found). Website percentages count how often a color is *declared*, not how much of the screen it covers. It does **not** read SVG images, screenshots of pages, PDFs or videos (see "Video Frame Extractor" for video frames), and it does **not** get past logins, CAPTCHAs or bot protection: a blocked site is reported as blocked.

**What you get**

- One dataset row per image or website: `dominantHex`, `dominantName`, a ranked `palette` (hex, rgb, hsl, name, percent, readable text color, contrast on white/black), `hexList`, best `contrastPairs`.
- `cssVariables` and `tailwindColors` blocks you can paste into a stylesheet or `tailwind.config.js`.
- Websites also return `themeColor`, `textColors`, `backgroundColors` and `customProperties` (CSS variables that hold a color).
- Bad URLs never stop the run. Failed items are free and listed in the `FAILED` record with the reason.

### How to get the dominant colors of an image from a URL

1. Put direct image links in `imageUrls`, for example `https://example.com/photo.jpg`.
2. Choose `colorsPerItem` (default 6) and the `method`: `kmeans` (smoother, default) or `median-cut` (classic, favors distinct colors).
3. Run it. `palette[0]` is the dominant color. Percentages add up to about 100 for an image. The same image always gives the same palette.

The image is shrunk to at most 180x180 pixels before counting,. Fully transparent pixels are ignored. Use `ignoreWhite` for product shots on a white background and `ignoreBlack` for images on black.

### How to find the color palette of a website

1. Put sites in `websiteUrls`, for example `https://www.python.org` (the `https://` is added if you leave it out).
2. The Actor fetches the page and up to 6 stylesheets once each, counts every color in `color`, `background`, `border`, `fill`, `stroke` and shadow declarations (hex, `rgb()`, `hsl()` and named colors), and ranks them.
3. By default `ignoreNeutrals` leaves white, black and grey out of the main `palette`, so brand colors come first. `textColors` and `backgroundColors` still list them. A site that only uses neutrals gets them back with a note.

### How to check which palette colors are readable together

Every row has `contrastPairs`: the best foreground/background pairs inside the palette with the WCAG contrast ratio and level (`AAA`, `AA`, `AA-large`, `fail`). Each palette color also has `textOnIt` (black or white, whichever reads better) plus `contrastOnWhite` and `contrastOnBlack`.

### How to turn a palette into CSS or Tailwind

Leave `includeSnippets` on (default). Each row then holds `cssVariables` (`:root { --color-1: #c23f10; ... }`) and `tailwindColors` (`colors: { 'palette-1': '#c23f10', ... }`).

### Input

| Field | Default | What it does |
|---|---|---|
| `imageUrls` | sample photo | Direct links to JPG, PNG, WebP, GIF, BMP or TIFF files. |
| `websiteUrls` | empty | Sites whose CSS colors you want. |
| `colorsPerItem` | 6 | 1 to 16 colors per item (images may return fewer if colors are similar). |
| `method` | `kmeans` | `kmeans` or `median-cut` (images only). |
| `ignoreWhite` / `ignoreBlack` | false / false | Skip near-white / near-black image pixels. |
| `ignoreNeutrals` | true | Websites: keep white, black and grey out of the main palette. |
| `includeSnippets` | true | Add CSS variables and Tailwind colors to each row. |
| `maxItems` | 100 | Hard cap on images plus websites per run (max 5000). |
| `maxImageMb` | 15 | Larger images are skipped, free (max 25). |
| `concurrency` | 5 | Items processed in parallel. |
| `timeoutSecs` / `retries` | 30 / 3 | Per download. |

At least one of `imageUrls` or `websiteUrls` is required.

Input example:

```json
{
  "imageUrls": ["https://interactive-examples.mdn.mozilla.net/media/cc0-images/grapefruit-slice-332-332.jpg"],
  "websiteUrls": ["https://www.python.org"],
  "colorsPerItem": 6,
  "method": "kmeans"
}
```

### Output

From a real local run of the grapefruit image above (palette shortened to 2 of 6 colors, snippets shortened):

```json
{
  "source": "https://interactive-examples.mdn.mozilla.net/media/cc0-images/grapefruit-slice-332-332.jpg",
  "type": "image", "status": "ok", "error": null, "method": "kmeans",
  "dominantHex": "#c23f10", "dominantName": "firebrick",
  "palette": [
    {"rank": 1, "hex": "#c23f10", "rgb": [194, 63, 16], "hsl": [16, 85, 41], "name": "firebrick", "percent": 44.9,
     "textOnIt": "#ffffff", "contrastOnWhite": 5.23, "contrastOnBlack": 4.01},
    {"rank": 2, "hex": "#d15b28", "rgb": [209, 91, 40], "hsl": [18, 68, 49], "name": "chocolate", "percent": 18.32,
     "textOnIt": "#000000", "contrastOnWhite": 4.01, "contrastOnBlack": 5.24}
  ],
  "hexList": ["#c23f10", "#d15b28"],
  "contrastPairs": [{"foreground": "#9f2708", "background": "#e5cebb", "ratio": 5.01, "wcag": "AA"}],
  "cssVariables": ":root { --color-1: #c23f10; ... }",
  "tailwindColors": "colors: { 'palette-1': '#c23f10', ... }",
  "width": 332, "height": 332
}
```

For `https://www.python.org` the same run found 623 color declarations over 3 stylesheets; the first palette entry was `#ffd343` (gold, 46 declarations), then `#3776ab`, with `themeColor` `#3673a5` and custom properties such as `--color-default: #444444`.

### How much does it cost

Pay per event: **$0.003 per palette extracted** ($3.00 per 1,000). Only items that really produced a palette are charged. Failed downloads, blocked sites, non-image files, sites with no static colors, invalid URLs, duplicates and items over `maxItems` are free. There is no start fee. Platform compute usage is billed by Apify on top, small because each item is one download and a short CPU pass (not yet measured on Apify).

| Job | Items | Charge |
|---|---|---|
| A designer checks 20 logos | 20 | $0.06 |
| A catalogue of product photos | 1,000 | $3.00 |
| A competitor survey of sites plus images | 10,000 | $30.00 |
| A large media library | 100,000 | $300.00 |

### Use cases

- Auto-tag a product catalogue or image library with its dominant color for filtering and search.
- Pick a brand palette from a logo and check which pairs pass WCAG contrast.
- Compare the CSS colors of competitor websites before a redesign.
- Generate CSS variables or Tailwind colors from a mood-board image.
- Pre-fill a placeholder background color for each image in a gallery or feed.

### FAQ

**Does it work on any website?** Only on sites whose colors are in static HTML and CSS files. Sites that build styles with JavaScript return `no-colors` (free) or a partial palette. A site that blocks plain requests is reported as `blocked`; the Actor does not try to get around that.

**Are website percentages the share of the screen?** No. They are the share of color declarations in the CSS, so a color used in many small rules ranks above a large background used once.

**Why do I get fewer colors than I asked for?** Colors that are nearly identical are merged, and a flat image simply has few colors.

**Are the results always the same?** Yes for images: the algorithms have no random start. Websites can change between runs when the site changes.

**Which images are accepted?** JPG, PNG, WebP, GIF (first frame), BMP and TIFF under `maxImageMb` and 60 megapixels. SVG is rejected with an explanation.

**Is it allowed to read any URL?** Only public http(s) addresses. Private, local and cloud-metadata addresses are blocked, also after redirects. Use it on images and sites you may process.

### Use with the Apify API / MCP / n8n / Make

Python:

```python
from apify_client import ApifyClient
client = ApifyClient("<APIFY_TOKEN>")
run = client.actor("<username>/color-palette-extractor").call(run_input={
    "imageUrls": ["https://example.com/photo.jpg"], "websiteUrls": ["https://www.python.org"], "colorsPerItem": 6})
for row in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(row["source"], row["dominantHex"], row["hexList"])
```

JavaScript:

```js
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: '<APIFY_TOKEN>' });
const run = await client.actor('<username>/color-palette-extractor').call({
  imageUrls: ['https://example.com/photo.jpg'], colorsPerItem: 6 });
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.map((r) => [r.source, r.dominantHex]));
```

The Actor works as a tool in MCP clients, and with the Apify nodes in n8n and Make: pass the input JSON above and read the dataset rows.

### Related tools

- Company Logo & Favicon Finder: Download Logos from Any Website (find the logo, then extract its palette here)
- Website Technology Checker: CMS, WordPress & Tracking Pixels
- Image Compressor & Resizer: Compress Images in Bulk
- Background Remover for Images (rembg, CPU)
- Video Frame Extractor (extract frames from a video, then run the frame URLs through this Actor)

# Actor input Schema

## `imageUrls` (type: `array`):

Direct links to image files (JPG, PNG, WebP, GIF, BMP, TIFF), one palette per image. Example: https://example.com/photo.jpg. SVG is not supported (it is vector markup, not pixels).

## `websiteUrls` (type: `array`):

Websites whose CSS colors you want, one palette per site. Example: https://www.python.org. Reads the static HTML and up to 6 linked stylesheets; styles built by JavaScript are not seen.

## `colorsPerItem` (type: `integer`):

How many colors to return for each image or website. Example: 6. Images: number of clusters (similar colors may be merged, so you can get fewer).

## `method` (type: `string`):

Algorithm used for images. Both are deterministic: the same image gives the same palette. Websites always use CSS declaration counts.

## `ignoreWhite` (type: `boolean`):

Skip near-white pixels (all channels 245 or more), useful for product photos on a white background.

## `ignoreBlack` (type: `boolean`):

Skip near-black pixels (all channels 10 or less), useful for images on a black background.

## `ignoreNeutrals` (type: `boolean`):

For websites, leave white, black and greys out of the main palette so brand colors come first. The text and background color lists still include them.

## `includeSnippets` (type: `boolean`):

Add ready-to-paste CSS variables and a Tailwind colors block to every row.

## `maxItems` (type: `integer`):

Hard cap on images plus websites processed in one run. Also caps your cost. Example: 100.

## `maxImageMb` (type: `integer`):

Images larger than this are skipped (free). Example: 15.

## `concurrency` (type: `integer`):

How many items are processed at the same time. Example: 5.

## `timeoutSecs` (type: `integer`):

Timeout for each download. Example: 30.

## `retries` (type: `integer`):

Attempts per download when the server answers 429/5xx or the connection fails. Example: 3.

## Actor input object example

```json
{
  "imageUrls": [
    "https://interactive-examples.mdn.mozilla.net/media/cc0-images/grapefruit-slice-332-332.jpg"
  ],
  "colorsPerItem": 6,
  "method": "kmeans",
  "ignoreWhite": false,
  "ignoreBlack": false,
  "ignoreNeutrals": true,
  "includeSnippets": true,
  "maxItems": 100,
  "maxImageMb": 15,
  "concurrency": 5,
  "timeoutSecs": 30,
  "retries": 3
}
```

# Actor output Schema

## `results` (type: `string`):

One row per image or website with its color palette, nearest names, contrast pairs and CSS/Tailwind snippets, as JSON, CSV, Excel and more.

## `records` (type: `string`):

Key-value store records: the run summary, notes on any problems, and any files.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "imageUrls": [
        "https://interactive-examples.mdn.mozilla.net/media/cc0-images/grapefruit-slice-332-332.jpg"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("data-done-right/color-palette-extractor").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "imageUrls": ["https://interactive-examples.mdn.mozilla.net/media/cc0-images/grapefruit-slice-332-332.jpg"] }

# Run the Actor and wait for it to finish
run = client.actor("data-done-right/color-palette-extractor").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "imageUrls": [
    "https://interactive-examples.mdn.mozilla.net/media/cc0-images/grapefruit-slice-332-332.jpg"
  ]
}' |
apify call data-done-right/color-palette-extractor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,data-done-right/color-palette-extractor"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/Cev8BFlRcVsBVdb1y/builds/61pDMXsldCAQEJl3x/openapi.json
