# Text Language Detector - ISO 639-3 + Confidence, 82 Langs (`eliai/text-language-detector`) Actor

Detect the language of up to 200 texts per run: ISO 639-3 code, English name, confidence and ranked alternatives (franc trigram model, in-process, texts never leave the run). $0.0005 per text — half the measured incumbent ($0.001); too-short snippets never charged. For routing and dataset splitting.

- **URL**: https://apify.com/eliai/text-language-detector.md
- **Developed by:** [Broke to Built](https://apify.com/eliai) (community)
- **Categories:** AI, Developer tools, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.40 / 1,000 detected languages

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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Language Detector - ISO 639-3 Code, Name and Confidence for 82 Languages

**Tell me what language this text is in.** You get the ISO 639-3 code, the English language name, a
confidence score, and the ranked runner-up candidates - for up to 200 texts in a single run.
Detection runs in-process with no external API call, so your texts never leave the run. $0.0005 per
text. Snippets too short to judge are recorded free.

Routing support tickets to the right queue, splitting a scraped dataset by language, filtering a
crawl down to one market, choosing a translation pipeline, tagging user-generated content: step one
is always detection, and it should cost almost nothing.

### What you get

Per text, one record with these exact fields:

- `ok` - true when a language was determined
- `text` - your input (truncated at 280 characters in the record)
- `iso639_3` - the detected code, e.g. `eng`, `spa`, `cmn`. `language` is an alias of this field.
- `name` - the English name of that language
- `confidence` - 0 to 1, the relative trigram score of the winner
- `alternatives` - up to 6 ranked candidates, each `{ iso639_3, name, score }`
- `error` - present instead of a verdict when the text is too short to detect. Never charged.

### Example 1: one text

Input:

```json
{ "text": "Questo e un esempio di testo scritto in italiano per il test." }
```

Output (real run, 2026-08-15, trimmed to the first three alternatives):

```json
{
  "ok": true,
  "iso639_3": "ita",
  "name": "Italian",
  "confidence": 1,
  "alternatives": [
    { "iso639_3": "ita", "name": "Italian", "score": 1 },
    { "iso639_3": "por", "name": "Portuguese", "score": 0.856 },
    { "iso639_3": "spa", "name": "Spanish", "score": 0.726 }
  ]
}
```

The winner always appears first in `alternatives` with score 1; the scores below it are relative, so
a close second (0.95+) is your signal that the text is short or the two languages are near
neighbours.

### Example 2: bulk, splitting a scraped dataset

Input:

```json
{
  "texts": [
    "El rápido zorro marrón salta sobre el perro perezoso.",
    "Le renard brun rapide saute par-dessus le chien paresseux.",
    "Der schnelle braune Fuchs springt über den faulen Hund."
  ],
  "maxTexts": 200
}
```

Returns three records, detected `spa`, `fra` and `deu` respectively, one charge each. Partition your
rows on `iso639_3` and you have the dataset split.

**When `texts` is filled, the single `text` field is ignored** - you are charged for the texts you
listed and nothing else.

### Example 3: a snippet too short to judge

Input:

```json
{ "text": "ok thx" }
```

Output:

```json
{ "ok": false, "text": "ok thx", "error": "Text too short to detect a language (needs ~20+ characters)" }
```

It declines rather than guessing, and that record is **not charged**. This matters when you are
running a support-ticket queue where a lot of messages are two words long.

### Pricing

**$0.0005 per text detected.** No start fee. One event covers one text analyzed and returned with
its code, name, confidence and ranked alternatives. A text under ~20 characters with no clear signal
is recorded as `ok: false` and never charged, so a noisy dataset does not bill you for the noise.

Honest comparison, read from the Apify Store on 2026-08-07: the direct incumbent
`bgfc97/language-detector` charges $0.001 per text. This is half that. Splitting a 10,000-row dataset
costs $5 here against $10 there.

Also honest: if you are already running Node or Python, the underlying approach (trigram detection,
via `franc` or `langdetect`) is an open-source library you can run locally for free. Pay for this
when you want it as a hosted step in a pipeline, in bulk, or as a tool an AI agent can call.

### When NOT to use this

- **Very short strings.** Product names, usernames, single words, search queries. Trigram detection
  needs roughly a sentence. Under ~20 characters it refuses rather than guessing.
- **Mixed-language documents.** One verdict per text, and it will be the dominant language. If you
  need per-paragraph or per-sentence language, split the text first and send the pieces.
- **Distinguishing near-identical languages with confidence.** Norwegian and Danish, Malay and
  Indonesian, Bosnian and Croatian and Serbian share enormous trigram overlap. Check `alternatives`:
  if the top two scores are within a few points, treat the result as "one of these two".
- **Languages outside the 82 covered.** Rarer languages get mapped to their nearest trigram
  neighbour rather than reported as unknown - a wrong answer with a confident-looking score.
- **Detecting the script rather than the language.** If all you need is "is this Cyrillic or Latin",
  a Unicode range check in your own code is free and exact.

### Honest limits

- Statistical trigram detection (franc-min 6.2.0, pinned), not a neural model. Excellent on
  sentences and paragraphs, unreliable on fragments.
- 82 languages, the franc-min set. Text in a language outside that set is forced into the closest
  match.
- `confidence` is a **relative** score, not a probability. 1 means "best of the candidates", not
  "certainly correct". The gap to the runner-up is the more informative number.
- A handful of rarer codes that can appear in `alternatives` have no English name in our lookup table
  and are shown with the ISO code repeated as the name (for example `glg`). The primary detection's
  `name` covers the mainstream languages.
- Up to 200 texts per run.

### FAQ

**How do I detect the language of a piece of text via API?**
Send `{"text": "..."}` and read `iso639_3` and `name`. For many texts, send `texts` as an array - up
to 200 per run, one record each.

**Why ISO 639-3 codes instead of the two-letter ones?**
639-3 is unambiguous. `cmn` is Mandarin specifically, where the 639-1 code `zh` blurs every Chinese
language together. If your stack needs 639-1, the mapping is a static lookup table on your side.

**How accurate is it?**
On a normal sentence or longer in one of the 82 supported languages, trigram detection is highly
reliable. Accuracy falls off with length, which is why anything under ~20 characters returns an
uncharged "too short" record instead of a coin flip.

**Does my text get sent to a third-party API?**
No. Detection runs inside the Actor process using a local model. Nothing is sent to an external
service, and the only place your text is written is your own run dataset.

**Can I split a scraped dataset by language?**
Yes, that is the main bulk use. Batch 200 rows per run, then partition on `iso639_3`. At $0.0005 per
row, 10,000 rows is $5.

**What does the confidence score actually mean?**
It is the winner's relative trigram score, normalized to 1. Use the distance to the second entry in
`alternatives` as your real confidence signal: a big gap is a firm verdict, a small gap means the
text is short or the languages are related.

**Why did some rows come back `ok: false`?**
The text was too short to detect (roughly under 20 characters with no clear signal). It is recorded
with the reason and never charged.

**Can an AI agent call this as a tool?**
Yes, through the Apify MCP server - useful for agents that need to route or translate incoming
messages before acting on them.

### Use from code or AI agents

```bash
curl -s "https://api.apify.com/v2/acts/EliAI~text-language-detector/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -X POST -H 'Content-Type: application/json' \
  -d '{"text": "Ceci est un exemple de texte en francais."}'
```

Agents: connect [Apify MCP](https://mcp.apify.com) and call the `EliAI/text-language-detector` tool.

- **Capability:** detect the language of one or many texts (ISO 639-3 + name + confidence + alternatives, 82 languages)
- **Required input:** `text` (string) or `texts` (array, or one newline-separated string)
- **Returns:** one record per text; `iso639_3` and `confidence` are the headline fields
- **Bounded:** 200 texts per run; failures isolate per text
- **Side effects:** none (in-process detection, texts never leave the run)

# Actor input Schema

## `text` (type: `string`):

A single piece of text to detect the language of. Works best with 20+ characters.

## `texts` (type: `array`):

Multiple texts to detect in one run. Each item is analyzed and charged separately. When this list is filled, the single text above is ignored, so you are only charged for the texts you listed.

## `maxTexts` (type: `integer`):

Maximum number of texts to process in one run (safety cap).

## Actor input object example

```json
{
  "text": "The quick brown fox jumps over the lazy dog.",
  "texts": [
    "El rápido zorro marrón salta sobre el perro perezoso.",
    "Le renard brun rapide saute par-dessus le chien paresseux.",
    "Der schnelle braune Fuchs springt über den faulen Hund."
  ],
  "maxTexts": 50
}
```

# Actor output Schema

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

Every item this run produced, as JSON.

## `resultsCsv` (type: `string`):

The same items as a spreadsheet-ready CSV.

# 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 = {
    "text": "The quick brown fox jumps over the lazy dog.",
    "texts": [
        "El rápido zorro marrón salta sobre el perro perezoso.",
        "Le renard brun rapide saute par-dessus le chien paresseux.",
        "Der schnelle braune Fuchs springt über den faulen Hund."
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("eliai/text-language-detector").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 = {
    "text": "The quick brown fox jumps over the lazy dog.",
    "texts": [
        "El rápido zorro marrón salta sobre el perro perezoso.",
        "Le renard brun rapide saute par-dessus le chien paresseux.",
        "Der schnelle braune Fuchs springt über den faulen Hund.",
    ],
}

# Run the Actor and wait for it to finish
run = client.actor("eliai/text-language-detector").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 '{
  "text": "The quick brown fox jumps over the lazy dog.",
  "texts": [
    "El rápido zorro marrón salta sobre el perro perezoso.",
    "Le renard brun rapide saute par-dessus le chien paresseux.",
    "Der schnelle braune Fuchs springt über den faulen Hund."
  ]
}' |
apify call eliai/text-language-detector --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,eliai/text-language-detector"
        }
    }
}

```

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/KZrXODvXVpgfbbqH1/builds/hcsCWhzZiCqApgqRl/openapi.json
