Group anagrams online
The anagram grouping tool takes a list of words and collects every entry that is made from the same letters, regardless of letter case.
Run — free
It keeps the original spelling of each word and the order in which words first appeared, so the result remains easy to compare with the source list. Use it to organize word-game candidates, check vocabulary collections, prepare exercises, or add a predictable grouping step to a text-processing workflow without writing and maintaining your own matching logic.
How anagram groups are identified
Two words belong to the same anagram group when their letters can be rearranged to produce the same case-insensitive character sequence. The tool creates a stable signature for every submitted word by converting it to lowercase, separating its characters, sorting those characters, and joining them again. Words with an identical signature enter the same cluster. For example, “Listen”, “silent”, and “enlist” share one signature even though their capitalization and letter order differ. The returned values keep the spelling supplied in the request; normalization is used only for comparison. Repeated letters matter, so “tap” does not match “tape,” and “pool” does not match “pol.” Punctuation, spaces, and accented characters are treated as characters rather than silently removed. This literal rule makes the result deterministic and prevents hidden cleanup from changing the meaning of the input. If a collection needs trimming, accent folding, or punctuation removal, perform that normalization before sending the words.
Preparing input and reading the result
Send the words field as an array containing at least one non-empty string. Each distinct letter signature produces one array inside the returned groups array. Groups appear in the order in which their first member occurs, and words inside each group retain their original input order. This makes results stable between runs and useful in tests, exports, and review screens. A word without an anagram companion still appears as a one-item group, because omitting it would lose information from the source list. The comparison is case-insensitive, but the output does not rewrite capitalization: “Tea” and “eat” are grouped together and returned exactly that way. The capability rejects a missing words field, a non-array value, an empty list, empty strings, non-string members, and requests beyond the published item limit. These errors are input errors rather than partial results, so a caller can correct the complete collection instead of receiving a group set built from silently discarded values.
Using deterministic grouping in a workflow
Anagram clustering is useful anywhere a collection must be partitioned by letter composition. A word-game service can group a dictionary subset before presenting possible plays. A teacher can build exercise sets that ask learners to recognize rearrangements. A data-quality pipeline can expose entries that differ only by character order, while keeping unmatched entries visible for inspection. Because the algorithm uses no network access, model inference, randomness, or current time, the same input always produces the same JSON result. That property makes the capability suitable for automated jobs whose outputs are compared, cached, or audited later. Processing runs locally in the browser on the free page, while API requests use the same pure solver for $0.002 per request. For very large dictionaries, split work into bounded batches and decide whether groups spanning batch boundaries must be merged by your application. For ordinary lists, one request gives a complete set of clusters ready to display or process further.
What you can do with it
Organize word-game candidates
Cluster a candidate list by letter composition before showing equivalent plays or puzzle answers.
Create language exercises
Turn a vocabulary list into stable groups for rearrangement, spelling, and pattern-recognition activities.
Inspect text datasets
Find entries that contain the same characters in a different order without losing unmatched words.
FAQ
Is matching case-sensitive?
No. Letter case is ignored when groups are formed, but every word keeps its original spelling in the output.
Are single words included?
Yes. A word with no matching anagram is returned as a one-item group so the result accounts for every input item.
Are spaces and punctuation ignored?
No. They are treated as characters. Normalize or remove them before the request if your definition of a word requires that.
What happens if the list is empty?
The request fails with an invalid input error because at least one word is required.
Does the tool change the order of my words?
No. Groups follow the first occurrence of each signature, and members remain in their original input order.
What does an API request cost?
Each API request costs $0.002. The same deterministic grouping is also available in the browser on this page.
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/text/anagram-groups \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"words":["listen","silent","enlist","stone","tones","Apple"]}'const res = await fetch("https://api.kit.forhosting.com/text/anagram-groups", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"words": [
"listen",
"silent",
"enlist",
"stone",
"tones",
"Apple"
]
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/text/anagram-groups",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"words": [
"listen",
"silent",
"enlist",
"stone",
"tones",
"Apple"
]
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/text/anagram-groups", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"words":["listen","silent","enlist","stone","tones","Apple"]}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"words":["listen","silent","enlist","stone","tones","Apple"]}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/text/anagram-groups", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"words": [
"listen",
"silent",
"enlist",
"stone",
"tones",
"Apple"
]
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "text.anagram_groups",
"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_items | 10000 |
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. |