# Unit and Currency Normalizer — NL/EU Notation Parser (`codeclouds/unit-and-currency-normalizer`) Actor

Parses NL/EU amount/unit text ('3.500 m²', '€1,2 mln', '15 ha', '2,5 ton') into structured number, category (area/weight/volume/length/percentage/currency), and optional normalized fields. Batch mode, optional ECB EUR conversion, deterministic, side-effect-free — built for AI-agent pipelines.

- **URL**: https://apify.com/codeclouds/unit-and-currency-normalizer.md
- **Developed by:** [Dennis](https://apify.com/codeclouds) (community)
- **Categories:** Developer tools, Other
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 normalized records

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## Unit and Currency Normalizer — NL/EU Notation Parser

Parses free text with amounts and units in Dutch/European notation (e.g. "3.500 m² grond", "€1,2 mln", "250.000,- excl. btw", "15 ha", "2,5 ton", "12,5%") into a structured result: parsed value, detected unit, unit category (area / currency / weight / volume / length / percentage / unknown), optional ISO currency code, optional normalized value/unit, optional ECB reference rate, and optional EUR conversion. Pure parsing logic — no API keys required; the optional ECB rate lookup uses the free, unkeyed ECB SDMX service. Designed as a deterministic, side-effect-free input-processing step for AI-agent pipelines (before comparison, aggregation, or filtering) so parse errors (like a factor-1000 mistake from dot/comma confusion) never reach downstream logic silently.

### When should an AI agent use this?

- "Convert '3.500 m² grond' and '15 ha' to the same base unit so I can compare them."
- "I have property listings in free Dutch text with amounts like '€1,2 mln' and '250.000,- excl. btw' — parse the numeric value and currency."
- "Before filtering real-estate records, normalize every area mention to m² and flag the confidence of each parse."
- "I have a batch of tender values in mixed currencies — convert each amount to EUR using today's ECB reference rates."
- "Normalize '500 l' and '2,5 m³' to a common volume unit so I can sum them for a logistics report."
- "Extract the numeric value and unit from a sentence like '2,5 ton staalschroot' for a materials-monitoring agent, and warn me if the parse is ambiguous."

### What this Actor does

- Parses NL/EU number notation: dot (`.`) = thousand separator, comma (`,`) = decimal separator.
- Detects units across six categories:
  - **Area:** `m²` / `m2`, `ha`, `km²` / `km2` (normalized to `m²`)
  - **Weight:** `kg`, `g`, `ton` / `t` (normalized to `kg`)
  - **Volume:** `m³` / `m3`, `l` / `liter` (normalized to `m³`)
  - **Length:** `km` (normalized to `m`)
  - **Percentage:** `%`
- Detects currency symbols (`€`, `$`, `£`) and maps to ISO codes (`EUR`, `USD`, `GBP`).
- Detects multipliers (`k`, `mln`, `mld`) and scales the value accordingly.
- Returns a `confidence` field (`high` / `medium` / `low`) per result.
- Returns `parseWarnings` (e.g. `no_recognized_unit`, `multiple_numbers_found_picked_first_N`) when the parse is incomplete or ambiguous.
- Optional `currencyConversion` flag: when `true`, fetches the latest ECB reference rate and adds `ecbRate`, `ecbRateValue`, `ecbRateCurrency`, `ecbRateDate`, and `normalizedCurrencyValue` (the amount expressed in EUR).
- **Batch mode:** pass an array of texts (`texts`) — each item produces one dataset record.

### Input

| Field | Type | Description |
|---|---|---|
| `text` | string | Single free text with amount and/or unit in NL/EU notation. Backward compatible. |
| `texts` | array of strings | Batch of texts to normalize in one run. If only `text` is given, it is treated as a single-item `texts` array. |
| `currencyConversion` | boolean | If `true`, fetch the ECB reference rate for detected currencies and add `ecbRate` + `normalizedCurrencyValue`. Default `false`. |

### Output

```json
{
  "sourceText": "3.500 m² grond",
  "value": 3500,
  "unit": "m²",
  "unitCategory": "area",
  "normalizedValue": 3500,
  "normalizedUnit": "m²",
  "confidence": "high",
  "parseWarnings": [],
  "currencyConversionRequested": false
}
```

With `currencyConversion: true` on a currency item:

```json
{
  "sourceText": "$1.000.000",
  "value": 1000000,
  "unit": "$",
  "unitCategory": "currency",
  "isoCurrency": "USD",
  "confidence": "medium",
  "ecbRate": { "rate": 0.92, "currency": "USD", "date": "2026-09-17", "source": "ecb-sdmx" },
  "ecbRateValue": 0.92,
  "ecbRateCurrency": "USD",
  "ecbRateDate": "2026-09-17",
  "normalizedCurrencyValue": 920000
}
```

Fields:

- `sourceText` — original input.
- `value` — parsed numeric value (after multiplier, before unit normalization).
- `unit` — detected unit string.
- `unitCategory` — `area` | `currency` | `weight` | `volume` | `length` | `percentage` | `unknown`.
- `normalizedValue` — value converted to base unit (`m²` for area, `kg` for weight, `m³` for volume, `m` for length). Only for recognized categories.
- `normalizedUnit` — base unit. Only for recognized categories.
- `isoCurrency` — `EUR`, `USD`, `GBP`, etc. Only when a currency symbol is detected.
- `confidence` — `high` (unit recognized), `medium` (currency without unit), `low` (unknown / no recognizable number).
- `parseWarnings` — array of human-readable warnings when the parse is incomplete or ambiguous.
- `ecbRate` / `ecbRateValue` / `ecbRateCurrency` / `ecbRateDate` — ECB reference-rate data (only when `currencyConversion: true`).
- `normalizedCurrencyValue` — the amount expressed in EUR (value × ECB rate). Only when both rate and value are available.

### Use cases

- **Real-estate data cleaning:** Normalize area descriptions in listings (NL property ads, appraisal reports) to a single `m²` column for comparison or aggregation.
- **Agent pipeline pre-processing:** Before an agent compares property values, runs a budget filter, or aggregates tender amounts, run this actor to eliminate silent parse errors from NL/EU notation.
- **Currency monitoring:** Convert mixed-currency amounts to EUR using ECB reference rates for cross-border tender or budget comparison.
- **Material / logistics parsing:** Convert `ton`, `kg`, `l`, `m³` to a single base value for reporting.
- **Batch ingestion:** Normalize a whole CSV/JSON column of free-text amounts in one API call.

### Pricing

- **Actor Start:** $0.00005 (Apify default)
- **Normalized record:** $0.002 per result

The only external network call is the optional ECB reference-rate lookup (when `currencyConversion: true`); it is free and unkeyed, so there is no variable external cost.

### Legal

No personal data, no scraping, no external data-source access during parsing. The optional ECB reference-rate lookup uses the free, public, unkeyed ECB SDMX REST service (`data-api.ecb.europa.eu/service`) with published open-data terms. No user-registration or licensing restrictions apply for this usage pattern.

### FAQ

**Q: Does it handle "250.000,- excl. btw"?**\
A: Yes — the trailing `,-` is stripped, the value is parsed as 250000, and the decimal/comma rules are applied correctly.

**Q: What about ambiguous currency like `$`?**\
A: Mapped to `USD` as the most common default. If the input contains an explicit ISO code (e.g. `USD 500`), future versions may prefer that.

**Q: How do I convert a batch of amounts to EUR?**\
A: Set `currencyConversion: true` and pass all texts in the `texts` array. Each currency item gets `ecbRate`, `ecbRateValue`, and `normalizedCurrencyValue` (amount in EUR).

**Q: How accurate is the unit detection?**\
A: Units are matched as a token directly after the number (e.g. `3.500 m²`), which avoids substring false-positives (`l` in `mln`, `t` in `beton`). Ambiguous or incomplete parses are reported via `confidence` and `parseWarnings` so downstream logic can decide.

### Related Actors

- **[url-to-structured-fact](https://apify.com/codeclouds/url-to-structured-fact)** — Verifies a URL and delivers structured source metadata; pairs well when the text being parsed comes from a web source this actor has just verified.

***

Zoekwoorden: parser, eenheid, valuta, m², ha, euro, bedrag, NL-notatie, agent-tool, normalisatie, volume, m³, liter, percentage

### Keywords

parser, normalization, currency, units, NL, EU, amount, text-parse, agent-tool, developer-tools, real-estate, property, m², ha, ton, kg, m³, liter, km, percentage, euro, euro-reference-rates, batch

### Changelog

#### 0.2.0

- **Batch mode:** `texts` array input; each item produces one dataset record (`text` remains backward compatible).
- **More unit categories:** volume (`m³`, `m3`, `l`/`liter` → `m³`), length (`km` → `m`), percentage (`%`).
- **Full EUR conversion:** when `currencyConversion: true`, adds `normalizedCurrencyValue` (amount in EUR) plus flat `ecbRateValue`/`ecbRateCurrency`/`ecbRateDate` fields for MCP-friendly, non-nested output.
- **`parseWarnings`:** array of warning codes when the parse is incomplete or ambiguous (`no_recognized_unit`, `multiple_numbers_found_picked_first_N`).
- **Unit matching hardened:** units are matched as a token directly after the number (regex with numeric prefix + word boundary), eliminating substring false-positives (`l` in `mln`, `t` in `beton`, `km` inside words).
- **Tests:** ECB fetch no longer depends on live network — replaced with a real-response fixture (`tests/fixtures/ecb_usd.csv`); 18 tests green.

#### 0.1.1

- V1.1 — ECB SDMX 2.1 REST-integratie (`ecb.ts`): bij `currencyConversion: true` wordt de meest recente ECB-referentiekoers opgehaald (`https://data-api.ecb.europa.eu/service/data/EXR`) en als `ecbRate` (rate, currency, date, source) toegevoegd aan de output. Alleen bij valuta-items; bij fouten of onbekende valuta blijft `ecbRate` weg zonder crash. Live probe bevestigd.

#### 0.1.0

- Initial release: NL/EU number parsing (dot = thousand, comma = decimal), unit detection (m², ha, km², kg, g, ton, t), currency symbol detection (€/$/£ → EUR/USD/GBP), multiplier detection (k, mln, mld), area/weight normalization to base units, confidence scoring.

# Actor input Schema

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

Free text with amount and/or unit in NL/EU notation (e.g. '3.500 m² grond', '€1,2 mln', '15 ha', '2,5 ton'). Use texts for batch.

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

Array of texts to normalize in one run. If only text is provided, it is treated as a single-item texts array.

## `currencyConversion` (type: `boolean`):

If true, fetch the ECB reference rate for detected currencies and add ecbRate + normalizedCurrencyValue. Default false.

## Actor input object example

```json
{
  "currencyConversion": false
}
```

# Actor output Schema

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

Results stored in the default dataset.

# 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("codeclouds/unit-and-currency-normalizer").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 = {}

# Run the Actor and wait for it to finish
run = client.actor("codeclouds/unit-and-currency-normalizer").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 '{}' |
apify call codeclouds/unit-and-currency-normalizer --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,codeclouds/unit-and-currency-normalizer"
        }
    }
}
```

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/rN0rLCOgQ3zQW92EU/builds/b28orus3oJvURLhL0/openapi.json
