Data Cleaner: Normalize Phone, URL, Price & Date Fields avatar

Data Cleaner: Normalize Phone, URL, Price & Date Fields

Pricing

from $0.50 / 1,000 cleaned rows

Go to Apify Store
Data Cleaner: Normalize Phone, URL, Price & Date Fields

Data Cleaner: Normalize Phone, URL, Price & Date Fields

Data cleaner from $0.50 per 1,000 rows ($0.80 on the Free plan): normalizes 6 field types in datasets, CSV, JSON or Excel: phone to E.164, email, URL, price and currency, date to ISO, company names. Works on nested fields and flags new, changed and removed rows since the last run.

Pricing

from $0.50 / 1,000 cleaned rows

Rating

0.0

(0)

Developer

Otama Labs

Otama Labs

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

2 days ago

Last modified

Share

Data cleaner for scraped and exported data: give it a JSON array, an Apify dataset or a CSV / JSON / Excel file, and it normalizes 6 field types in every row: phone numbers to E.164, emails, URLs (canonical form, no tracking parameters), prices (amount + ISO currency), dates (ISO 8601) and company names (legal suffixes removed, near-duplicates grouped). It works on nested fields (contact.phone) and can compare with the last run to flag new, changed and removed rows.

From $0.50 per 1,000 rows ($0.80 on the Free plan): 10,000 rows cost $5 to $8. Rows that are left out (unchanged rows with Only new and changed rows) and removed-row markers are free.

What you can use it for

  • Clean scraper output before it goes into a CRM, Google Sheets or a database: one phone format, one date format, one URL per site.
  • Merge lists from several sources: company_key / company_group match "Acme Corp." with "ACME Corporation"; contact_website_domain matches www.acme.com/?utm_source=x with https://acme.com.
  • Price monitoring: $1,299.99, 1.299,99 €, ¥12,000 and 2.5k USD become numbers with a currency code you can sort and convert.
  • Track a feed or catalog over time: set a key field (id, sku, url) and get _change: new / changed / unchanged / removed for every row.
  • AI agents: hand messy rows to the Actor and get typed values back, with a reason for every value it could not read.

Output example

Your row stays as it is; the cleaned values are added next to it (dots in nested names become _). Real output of the default input:

{
"id": "A-1",
"company": "Acme Corp.",
"contact": { "phone": "(415) 555-0132", "website": "www.acme.com/?utm_source=list" },
"price": "$1,299.99",
"updatedAt": "03/04/2026",
"company_clean": "Acme",
"company_key": "acme",
"company_group": "acme",
"contact_phone_e164": "+14155550132",
"contact_phone_country": "US",
"contact_phone_national": "(415) 555-0132",
"contact_phone_extension": null,
"contact_website_canonical": "https://acme.com/",
"contact_website_domain": "acme.com",
"price_amount": 1299.99,
"price_currency": "USD",
"updatedAt_iso": "2026-03-04",
"_issues": [
{ "field": "updatedAt", "value": "03/04/2026", "issue": "day and month could be swapped; read as MDY" }
]
}

Values that cannot be read become null and are listed in _issues with the reason, so nothing is silently guessed.

Field types

TypeAdded columnsExamples
phone_e164, _country, _national, _extension(415) 555-0132 → +14155550132; 03-1234-5678 with country JP → +81312345678
email_normalized, _domainmailto:Ann@Example.COM → Ann@example.com
url_canonical, _domainHTTPS://Shop.Acme.co.uk/products/?utm_source=x → https://shop.acme.co.uk/products, domain acme.co.uk
price_amount, _currency1.299,00 € → 1299.0 EUR; R$ 10,00 → 10.0 BRL; 2.5k USD → 2500.0 USD
date_isoOct 5, 2026 → 2026-10-05; 2026年10月1日 → 2026-10-01; unix timestamps; yesterday
company_clean, _key, _groupGlobex, Inc → Globex, key globex; 株式会社サンプル → サンプル

How to use

  1. Paste your rows into Rows (JSON array), or enter an Apify dataset ID (for example the output of a scraper run), or a File URL of a CSV, JSON, JSON Lines or XLSX file.
  2. Leave Fields and their types empty to detect fields by name (phone, tel, email, website, url, price, cost, salary, createdAt, date, company, employer...), or name them yourself: {"contact.tel": "phone", "cost": "price", "vendor": "company"}.
  3. Set the country for phone numbers without a +, the order of numeric dates (03/04/2026 is March 4 in MDY, 3 April in DMY) and the currency for $ / ¥ / plain numbers.
  4. Click Start. The default input cleans 5 sample rows in a few seconds. Download the result as JSON, CSV or Excel, or read it through the API.

To compare with the last run, set Key field (e.g. id) and keep the same Compare name across runs. Turn on Output only new and changed rows to get just the changes (unchanged rows are not output and not charged).

Input

FieldWhat it does
Rows (JSON array)Your rows. Nested objects are fine.
Apify dataset IDClean the items of a dataset instead.
File URLCSV (comma, semicolon, tab or pipe), JSON, JSON Lines or XLSX (first sheet), up to 50 MB.
Fields and their types{"field": "type"}; types phone, email, url, price, date, company. Dots for nested fields.
Detect fields by nameOn by default. Fields you name win.
Country for phone numbersTwo-letter code, default US.
Order of numeric datesMDY (default), DMY or YMD. Day/month values that could be swapped get a note in _issues.
Currency for $, ¥, krDefault USD. $ follows it when it is a dollar currency (CAD, AUD...), ¥ when it is JPY or CNY.
Decimal separatorAuto, dot or comma.
URL optionsRemove tracking parameters (utm_*, gclid, fbclid...) and www. (both on by default).
Company name match0-100, default 90: how similar cleaned names must be to share a _group.
Key field / Compare name / Only new and changed rowsCompare with the last run.
Max rows0 = all, up to 100,000 rows per run.

Compare with the last run

With a key field, each row gets _key and _change:

  • new: the key was not in the last run with this compare name.
  • changed: the original row differs from the last run (the comparison uses your original values, so a relative date like yesterday does not mark every row as changed).
  • unchanged: same as last time.
  • removed: a key of the last run that is not in this run. These rows contain only _key and _change and are free.

The state is saved in your account only when every row was delivered, so a run that hit your cost limit does not hide changes next time.

Pricing

Pay per event:

EventPrice
Cleaned row$0.80 per 1,000 on the Free plan, $0.70 Bronze, $0.60 Silver, $0.50 Gold and up
Actor start$0.00005 per GB of memory per run (default memory 512 MB = one start)

Examples: the default input (5 rows) costs under $0.01; 10,000 rows cost $5 to $8. Platform usage is included. Set a maximum cost per run in the run options and the Actor stops at that limit.

Limits

  • It checks formats, not existence: a phone number with a valid area code and length is accepted even if nobody uses it.
  • A date without a year (Oct 5) gets the current year and a note in _issues. Text without any digit is only read as a date when it is a relative word (yesterday, today, 3 hours ago).
  • Company names: legal forms (Inc, Ltd, LLC, GmbH, 株式会社...) are removed; brand words are kept. Fuzzy grouping is used for the first 5,000 different names in a run, exact keys after that.
  • Files: UTF-8 is best; Shift_JIS and Windows-1252 CSV files are also read. Old .xls files are not supported (save as .xlsx or CSV). Only the first sheet of an XLSX file is read.
  • Up to 100,000 rows per run. If a run is cut by Max rows or your cost limit, the comparison state is not saved.
  • Running it again on its own output does not clean the added columns again (_e164, _key... are skipped by the field detection).

For AI Agents

Call the Actor through the Apify API or the Apify MCP server (https://mcp.apify.com/?tools=tamatama/data-normalizer). Example input:

{
"data": [{ "name": "Acme Corp.", "tel": "+1 (415) 555-0132", "web": "acme.com", "cost": "€19,90", "date": "23.10.2026" }],
"fields": { "name": "company", "tel": "phone", "web": "url", "cost": "price", "date": "date" },
"dateOrder": "DMY"
}

Read the cleaned values from the dataset and the reasons for unread values from _issues.

FAQ

Does it change my original values? No. The original row is kept and the cleaned values are added as new columns.

Does it guess when a value is ambiguous? It follows your settings (date order, country, currency) and writes a note in _issues for values that could be read two ways, such as 03/04/2026.

Does it check that a phone number or email exists? No. It checks the format and the numbering plan (a valid area code and length), not whether the line or mailbox is in use. It does not contact anyone.

Does it call other services? No. All parsing runs inside the Actor. Only the file URL you give is downloaded.

Can I use it from Make, n8n, Zapier or LangChain? Yes: use the Apify app or integration of the tool and pick this Actor, or call the REST API (POST https://api.apify.com/v2/acts/tamatama~data-normalizer/run-sync-get-dataset-items). To clean a scraper's output automatically, add this Actor as an integration of the scraper's task and pass the dataset ID.

Which countries and currencies? Phone numbers of all countries (Google's libphonenumber data). Currency codes in ISO form and the common symbols (€ £ ₹ ₩ R$ zł and others).

ActorWhat it does
PDF to MarkdownPDF, Word, Excel and PowerPoint to Markdown and RAG chunks.
PDF OCRScanned PDFs and images to text.
Website Change MonitorText diff of web pages between runs.
ATS JobsCompany job boards (Greenhouse, Lever, Ashby and more) in one format.
Remote JobsRemote OK and Jobicy remote jobs.

Libraries

phonenumbers (Apache-2.0, a port of Google's libphonenumber), dateparser (BSD-3-Clause), price-parser (BSD-3-Clause), rapidfuzz (MIT), tldextract (BSD-3-Clause, with its bundled public suffix list), openpyxl (MIT).

Data sources

The Actor reads only the data you give it (rows, a dataset in your account, or a file URL). Use it on data you are allowed to process.