Redact common PII patterns in text
Mask emails, phone numbers and card-like digit runs before a text reaches logs or tickets: in the example, two emails, one phone and one card number become [EMAIL_1], [EMAIL_2], [PHONE_1] and [CREDIT_CARD_1], with a total of 4. Free in your browser.
- Free
- Runs in your browser
- No sign-up
- Your data stays on your device
Run — free
Redact common personal-data patterns before text reaches logs, tickets, analytics, or shared documents. This deterministic tool finds email addresses, familiar phone-number formats, and credit-card-like sequences containing 13 to 19 digits, then replaces every match with a numbered label such as [EMAIL_1], [PHONE_1], or [CREDIT_CARD_1]. It returns the cleaned text plus counts by category. Processing uses pattern matching only: it does not contact a service, infer identities, retain submitted text, or claim that every match is verified personal information.
Redact common identifiers before text travels farther
Operational text often moves through more systems than its author expects. A support message may be copied into an issue, indexed for search, included in an analytics event, and pasted into a team conversation. An email address or telephone number that was useful in the original exchange can become unnecessary exposure everywhere downstream.
This capability gives applications a predictable cleanup step before that movement begins. Submit one text value and receive the same text with recognized patterns replaced by numbered labels. Numbering preserves useful structure: repeated categories remain distinguishable, and a reviewer can understand that two separate email-shaped values appeared without seeing either value.
The result also includes category totals, which can support quality checks without returning the sensitive matches themselves. Because the algorithm is deterministic and uses no network access, the same input produces the same output.
Understand exactly what the matcher recognizes
The matcher targets three practical pattern families. Email matching requires a conventional local part, an at sign, and a dotted domain. Phone matching recognizes common international and domestic layouts that use spaces, periods, hyphens, or parentheses, including forms such as an international prefix followed by grouped digits.
Credit-card-like matching looks for 13 through 19 digits, optionally separated by spaces or hyphens. Card candidates are intentionally described as card-like: the tool does not run an issuer lookup or a checksum and therefore can mask account numbers or other long digit sequences too. Matches are evaluated in an ordered pass so a long card-like sequence is not partly rewritten as a phone number, and inserted placeholders are never scanned again.
The tool does not identify names, street addresses, national identifiers, dates of birth, IP addresses, or context-dependent secrets. It also cannot guarantee that every real email or phone notation will match. Treat the result as focused pattern reduction, not a certification that text is anonymous or safe to publish.
Use the output safely in an automated workflow
Place redaction as early as practical, ideally before an application writes untrusted text to durable logs or sends it to another processor. A total of zero means no supported pattern was found; it does not prove the absence of personal data. If a workflow requires stronger assurance, combine this deterministic pass with domain-specific validation, access controls, retention limits, and a separate review process.
Avoid storing the original text merely to compare it with the cleaned version, since that can defeat the purpose of masking. Numbered placeholders are designed to remain readable in tickets and reports, but they are not reversible tokens and contain no recovery data. Empty or whitespace-only input is rejected as invalid instead of returning a misleading successful result.
Test representative material from your own sources because regional phone conventions and unusual email syntax vary.
What you can do with it
Clean application logs
Mask common contact and payment-number patterns before messages enter centralized logging and search systems.
Prepare support conversations
Remove recognizable email, phone, and card-like values before sharing ticket excerpts for training or investigation.
FAQ
What patterns are masked?
The tool masks conventional email addresses, common formatted phone numbers, and sequences containing 13 to 19 digits with optional spaces or hyphens.
Does it verify that a card number is valid?
No. Long digit sequences are treated as credit-card-like patterns without issuer checks or checksum validation, favoring masking over classification certainty.
Does a clean result prove that the text contains no personal data?
No. Names, addresses, regional formats, contextual identifiers, and unsupported patterns may remain. Use additional controls when complete de-identification is required.
Are the placeholders reversible?
No. A placeholder records only the category and occurrence number; the returned result contains no mapping back to the matched value.
Why are the labels numbered instead of all being the same?
So the text keeps its structure: repeated categories stay distinguishable, and a reviewer can tell that two different email addresses appeared without seeing either one. The totals per category also allow quality checks without exposing the values.
Related tools
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/data/remove-pii-patterns \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"text":"Email alex@example.com, call +1 (415) 555-0198, or reference card 4111 1111 1111 1111."}'const res = await fetch("https://api.kit.forhosting.com/data/remove-pii-patterns", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"text": "Email alex@example.com, call +1 (415) 555-0198, or reference card 4111 1111 1111 1111."
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/data/remove-pii-patterns",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"text": "Email alex@example.com, call +1 (415) 555-0198, or reference card 4111 1111 1111 1111."
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/data/remove-pii-patterns", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"text":"Email alex@example.com, call +1 (415) 555-0198, or reference card 4111 1111 1111 1111."}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"text":"Email alex@example.com, call +1 (415) 555-0198, or reference card 4111 1111 1111 1111."}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/data/remove-pii-patterns", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"text": "Email alex@example.com, call +1 (415) 555-0198, or reference card 4111 1111 1111 1111."
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "data.remove_pii_patterns",
"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_mb | 25 |
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. |
Technical notes
Use the output safely in an automated workflow
Read the redacted_text field as the transformed document and the counts object as a compact audit signal. For API automation, each submitted text item costs $0.002; the browser version can run the same pure logic locally.
Integration use cases
Sanitize development fixtures
Turn copied production-like text into safer test material while retaining the location and category of each replacement.
Technical questions
What happens when the input is empty?
An empty or whitespace-only text value returns an invalid_input error rather than a successful empty transformation.
How much does an API request cost?
Each text item costs $0.002 per request. The browser runner uses the same deterministic logic locally.