piidetectionapi.com
Home
Solutions - Fundamentals
What Is PII Detection? NER vs Regex vs Rules Accuracy, Precision & Recall PII in Test Data
Solutions - Compliance
GDPR Personal Data HIPAA PHI Detection CCPA / CPRA PCI DSS Card Data
Solutions - AI & LLM Safety
LLM Guardrails Chatbot PII Filtering RAG Pipelines
Solutions - Data Discovery & DLP
Data Loss Prevention Log File Scanning Support Tickets Email Scanning Documents & PDFs Database Discovery ETL & Streaming Pipelines
Industries - Financial
Banking Fintech Insurance
Industries - Healthcare
Healthcare Pharma & Clinical Trials Telehealth
Industries - Public Sector & Legal
Government & FOIA Law Enforcement Law Firms & eDiscovery Education (FERPA)
Industries - Technology
SaaS Platforms Cybersecurity & IR Telecommunications Gaming & Platforms
Industries - Other
HR & Recruiting Retail & E-commerce Call Centers & BPO Real Estate Travel & Hospitality Marketing & AdTech
How-to Guides - Identity & Contact
Detect Names Detect Email Addresses Detect Phone Numbers Detect Physical Addresses Detect Dates of Birth
How-to Guides - IDs & Financial
Detect SSNs Detect Passport Numbers Detect Drivers Licenses Detect Credit Card Numbers Detect Bank Accounts & IBAN
How-to Guides - Technical & Health
Detect IP & Device IDs Detect Medical Records & PHI
Resources
Pricing API Docs Supported Entities Languages About Contact Sign In Try the Live Demo Get Started
How-To Guide

How to Detect IP Addresses & Device Identifiers

Learn how to automatically find IPv4 and IPv6 addresses, MAC addresses, device IDs, IMEI numbers, cookies, and user-agent strings in text, logs, and telemetry using PII Detection API — and understand when network identifiers count as personal data under GDPR.

12 min read
Code examples included
Updated Aug 2026

Overview

IP addresses and device identifiers are among the most pervasive forms of personally identifiable information in modern systems — and among the most frequently overlooked. Unlike a name or an email address, an IP address rarely looks "personal" to the engineer scrolling past it in an application log. Yet regulators in Europe and several US states have repeatedly confirmed that network and device identifiers can single out an individual, which places them squarely inside the scope of GDPR, CCPA/CPRA, and the ePrivacy rules that govern cookies and tracking technologies.

The problem is scale. A single production web server can write hundreds of thousands of client IPs to its access logs every day. Mobile backends collect device IDs and IMEI numbers with every crash report. Support agents paste router configurations containing MAC addresses into tickets. Analytics pipelines ingest raw user-agent strings that fingerprint browsers with surprising precision. Finding all of these identifiers by hand — or with brittle homegrown regex — is not realistic once data volume grows.

PII Detection API solves this with a single endpoint that scans free text for 150+ entity types, including the full family of network and device identifiers: IP_ADDRESS, MAC_ADDRESS, DEVICE_ID, IMEI, COOKIE, and USER_AGENT. The API returns each match with its exact character offsets and a confidence score, and can optionally hand back a masked version of the input in the same call, so you can log, store, or forward the sanitized text immediately.

Before Detection
2026-08-25 10:14:02 GET /account 200 client=203.0.113.45 mac=00:1B:44:11:3A:B7 ua="Mozilla/5.0 (iPhone; CPU iPhone OS 17_4)"
After Masking
2026-08-25 10:14:02 GET /account 200 client=[IP_ADDRESS] mac=[MAC_ADDRESS] ua=[USER_AGENT]
IPv4 + IPv6
Detects dotted-quad IPv4, full and compressed IPv6, ports, and CIDR notation
Device Identifiers
MAC addresses, IMEIs, advertising IDs, cookies, and user-agent strings
Log-Scale Speed
Batch up to 50,000 characters per request for high-volume log scanning

Why Network Identifiers Are PII

The instinct to treat IP addresses as harmless infrastructure data is understandable — they identify machines, not people. But in practice a network identifier almost always maps back to a person or a small household, and both courts and regulators have caught up with that reality. Detecting these identifiers is therefore not an academic exercise; it is a compliance requirement for most organizations that operate at scale.

The Legal Landscape

  • GDPR (EU): Recital 30 explicitly names IP addresses, cookie identifiers, and RFID tags as "online identifiers" that may be used to profile and identify natural persons. The CJEU's Breyer judgment (C-582/14) confirmed that even dynamic IP addresses are personal data for a website operator when a legal means exists — via the ISP — to link the address to an individual.
  • CCPA/CPRA (California): The statutory definition of personal information expressly includes IP addresses and "unique personal identifiers" such as device identifiers, cookies, and advertising IDs, whenever they can reasonably be linked to a consumer or household.
  • ePrivacy Directive: Cookie values and comparable device-fingerprinting data require consent in most EU member states, which means stored cookie identifiers are regulated data by definition.
  • HIPAA (US healthcare): IP addresses and device identifiers/serial numbers are two of the eighteen Safe Harbor identifiers that must be removed to de-identify protected health information — see our HIPAA PHI detection guide.

Where These Identifiers Hide

Network and device identifiers accumulate in places that traditional data-inventory exercises rarely reach:

  • Web server and application logs: client IPs on every request line, plus forwarded-for chains that record the entire proxy path.
  • Crash reports and telemetry: device IDs, IMEIs, and OS fingerprints bundled automatically by mobile SDKs.
  • Support tickets and chat transcripts: users and agents paste ipconfig/ifconfig output, router pages, and traceroutes containing IPs and MAC addresses.
  • Security tooling: SIEM events, IDS alerts, and firewall exports are essentially structured lists of IP addresses tied to behavior.
  • Analytics exports: raw clickstream data with cookie IDs and full user-agent strings that can fingerprint an individual browser.

Tip: A user-agent string alone is rarely identifying, but combined with an IP address and a timestamp it often is. Detection policies should treat these identifiers as a family, not as isolated types — which is why the API lets you request all six in a single call.

Quick Start

The example below scans a log excerpt for the complete set of network and device identifiers. You need an API key — get one free from the get started page or explore the interactive demo first, then send a single POST request:

import requests

resp = requests.post(
    "https://piidetectionapi.com/api/moderate.php",
    json={
        "api_key": "YOUR_API_KEY",
        "api_type": "pii_detection",
        "text": "Login from 203.0.113.45 (fe80::1ff:fe23:4567:890a), "
                "MAC 00:1B:44:11:3A:B7, IMEI 490154203237518.",
        "entities": ["IP_ADDRESS", "MAC_ADDRESS", "DEVICE_ID",
                     "IMEI", "COOKIE", "USER_AGENT"],
        "mask_mode": "replace",
    },
    timeout=30,
)
data = resp.json()
for e in data["detected_entities"]:
    print(e["type"], e["text"], e["start"], e["end"], e["confidence"])
const resp = await fetch("https://piidetectionapi.com/api/moderate.php", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    api_key: "YOUR_API_KEY",
    api_type: "pii_detection",
    text: "Login from 203.0.113.45 (fe80::1ff:fe23:4567:890a), MAC 00:1B:44:11:3A:B7, IMEI 490154203237518.",
    entities: ["IP_ADDRESS", "MAC_ADDRESS", "DEVICE_ID", "IMEI", "COOKIE", "USER_AGENT"],
    mask_mode: "replace",
  }),
});

const data = await resp.json();
data.detected_entities.forEach(e =>
  console.log(e.type, e.text, e.start, e.end, e.confidence)
);
curl -X POST https://piidetectionapi.com/api/moderate.php \
  -H "Content-Type: application/json" \
  -d '{
    "api_key": "YOUR_API_KEY",
    "api_type": "pii_detection",
    "text": "Login from 203.0.113.45 (fe80::1ff:fe23:4567:890a), MAC 00:1B:44:11:3A:B7, IMEI 490154203237518.",
    "entities": ["IP_ADDRESS", "MAC_ADDRESS", "DEVICE_ID", "IMEI", "COOKIE", "USER_AGENT"],
    "mask_mode": "replace"
  }'

The response lists every match with its type, exact position, and confidence, plus the masked text:

{
  "detected_entities": [
    {"type": "IP_ADDRESS", "text": "203.0.113.45", "start": 11, "end": 23, "confidence": 0.99},
    {"type": "IP_ADDRESS", "text": "fe80::1ff:fe23:4567:890a", "start": 25, "end": 49, "confidence": 0.98},
    {"type": "MAC_ADDRESS", "text": "00:1B:44:11:3A:B7", "start": 56, "end": 73, "confidence": 0.99},
    {"type": "IMEI", "text": "490154203237518", "start": 80, "end": 95, "confidence": 0.97}
  ],
  "anonymized_text": "Login from [IP_ADDRESS] ([IP_ADDRESS]), MAC [MAC_ADDRESS], IMEI [IMEI].",
  "entities_detected": 4,
  "processing_time_ms": 142,
  "mask_mode_used": "replace",
  "status": 200
}

IPv4 vs IPv6 Detection

Both address families are returned under the single IP_ADDRESS entity type, but they present very different detection challenges, and it is worth understanding what the model handles for you.

IPv4: Deceptively Simple

An IPv4 address is four decimal octets separated by dots — 203.0.113.45 — which sounds trivial to match. In real text, however, naive patterns collapse quickly. Version strings like 2.4.1.100, section numbers, decimal-separated timestamps, and SNMP OIDs all look like dotted quads. A pure regex approach either misses valid addresses or floods you with false positives. PII Detection API validates each octet range (0–255) and, more importantly, weighs the surrounding context: a dotted quad following "connected from" or inside an nginx log line scores high; the same pattern inside "upgraded to release 2.4.1.100" scores low and is suppressed by the default 0.5 threshold.

IPv6: Structurally Complex

IPv6 addresses are eight groups of hexadecimal digits with aggressive abbreviation rules: leading zeros drop, one run of zero groups can collapse to ::, IPv4-mapped forms embed a dotted quad (::ffff:192.0.2.128), and link-local addresses may carry a zone index (fe80::1%eth0). The API's detector normalizes all of these forms, including bracketed addresses with ports ([2001:db8::1]:443) as they appear in URLs and log lines. Because IPv6 addresses are frequently unique per device — and privacy extensions notwithstanding, often stable per session — they are at least as identifying as IPv4 and should never be excluded from a scanning policy.

Ports, CIDR, and Ranges

Log data rarely contains bare addresses. You will see 203.0.113.45:52114 (address plus ephemeral port), 10.0.0.0/8 (CIDR blocks in firewall rules), and ranges in blocklists. The detector isolates the address component so offsets point at exactly the identifying substring, which matters when you redact: masking the port or the prefix length would corrupt otherwise useful network documentation.

Note on private ranges: Addresses in RFC 1918 space (10.x, 172.16–31.x, 192.168.x) and IPv6 unique-local space identify machines inside your own network rather than external individuals. They are still detected — internal IPs can identify employees — but if your policy deliberately excludes them, use custom_instruction (for example, "do not flag private RFC 1918 IP ranges") to suppress them without writing any post-processing code.

Device Identifier Types

IPs are only one branch of the device-identifier family. The API detects five further types that, individually or in combination, can single out a device and therefore its user. The table below summarizes each entity type, its typical shape, and where it usually appears.

Entity TypeExampleWhat It IdentifiesCommon Sources
IP_ADDRESS 203.0.113.45
2001:db8::8a2e:370:7334
Network endpoint; maps to a subscriber via the ISP Web/app logs, firewalls, email headers, VPN records
MAC_ADDRESS 00:1B:44:11:3A:B7 Physical network interface; globally unique per NIC DHCP logs, Wi-Fi analytics, router configs, support tickets
DEVICE_ID IDFA/AAID GUIDs, e.g. 6D92078A-8246-4BA4-AE85-1BC39E6EAAD7 A specific phone, tablet, or installation Mobile SDK telemetry, ad-tech payloads, crash reports
IMEI 490154203237518 Cellular handset hardware; survives factory resets Carrier records, MDM inventories, theft reports, repair tickets
COOKIE session_id=a3fWx91b2c… A browser profile across visits HTTP request dumps, analytics exports, HAR files
USER_AGENT Mozilla/5.0 (iPhone; CPU iPhone OS 17_4)… Browser/OS fingerprint; identifying in combination Access logs, bug reports, bot-detection systems

MAC Addresses

A MAC address is burned into the network interface at manufacture, making it one of the most persistent identifiers that exists — it survives reinstalls, IP changes, and network moves. The detector recognizes colon-, hyphen-, and dot-separated notations (00:1B:44:11:3A:B7, 00-1B-44-11-3A-B7, Cisco-style 001B.4411.3AB7) and uses context to separate MACs from other hex strings such as commit hashes or UUID fragments.

IMEI Numbers

The 15-digit IMEI uniquely identifies a cellular handset and is validated with the Luhn check digit, which eliminates most random 15-digit false positives. IMEIs turn up in places engineers forget: MDM exports, insurance claims, "find my phone" support conversations, and carrier API responses. Because an IMEI persists across SIM swaps and factory resets, regulators treat it as a strong personal identifier — HIPAA lists device identifiers and serial numbers among its 18 Safe Harbor identifiers.

Cookies and User Agents

Cookie identifiers are pseudonymous by design, but that is precisely why they are regulated: their entire purpose is to recognize the same person on a return visit. The detector flags high-entropy identifier values in cookie syntax (name=value pairs in Cookie/Set-Cookie headers or query dumps). User-agent strings are detected as complete units so a single mask replaces the whole fingerprint. When your analytics genuinely need coarse browser statistics, mask user agents with mask_mode: "hash" instead of removal — identical agents hash to identical tokens, so aggregate counts survive while the raw fingerprint disappears.

When IP Addresses Are Personal Data Under GDPR

This question generates more engineering-legal debate than almost any other in privacy, so it deserves a precise answer. Under GDPR, data is personal when it relates to an identified or identifiable natural person, and identifiability is judged by "all the means reasonably likely to be used" by the controller or by another person (Recital 26).

The Practical Rules of Thumb

  • Static IPs: effectively always personal data. A static address assigned to a residential subscriber is a persistent identifier comparable to a phone number.
  • Dynamic IPs: personal data for the ISP (which holds the assignment records), and — per the CJEU's Breyer ruling — also for a website operator, because legal channels exist through which the operator could obtain the link between address and subscriber, for example during criminal proceedings.
  • IPs plus timestamps: the combination is what makes re-identification realistic. A bare address list is weakly identifying; an address-timestamp pair matched against ISP records identifies a subscriber precisely. Most logs store exactly this combination.
  • Truncated or hashed IPs: zeroing the final octet (a common analytics practice) or hashing addresses reduces risk, but supervisory authorities generally treat these as pseudonymization, not anonymization — the data stays inside GDPR scope, though with a materially improved risk profile.

The engineering consequence is straightforward: if your logs, tickets, or exports contain client IPs, you are processing personal data, and every GDPR duty attaches — lawful basis, minimization, retention limits, breach notification, and data subject access. Detection is the mechanism that makes those duties operational: you cannot minimize, delete, or disclose what you have not found. Our GDPR PII detection guide covers the full compliance workflow, and the DLP guide shows how to enforce policies automatically at egress points.

Practical pattern: keep raw IPs only in a short-retention hot store for security operations (a legitimate-interest purpose recognized by Recital 49), and run every longer-lived copy — analytics exports, ticket archives, training datasets — through the detection API with mask_mode: "hash". Security teams keep correlation ability; the archive stops accumulating raw identifiers.

Detecting IPs and Device IDs in Log Files

Log files are the highest-volume habitat of network identifiers, and they have properties that make detection both easier and harder than in prose. Easier, because log formats are semi-structured and the model's context signals are strong. Harder, because volume is enormous and log lines mix identifying values with operationally similar-looking noise.

A Pipeline That Works

  1. Batch lines into chunks. Concatenate log lines up to the 50,000-character request limit rather than sending one line per call. This cuts request overhead by two orders of magnitude and preserves cross-line context.
  2. Scan with a scoped entity list. Pass only the identifier types your policy covers — restricting entities to the six network/device types is faster and eliminates irrelevant matches in log noise.
  3. Choose the right mask mode. replace for human-readable sanitized logs, hash when downstream systems still need to group events by client, redact for exports leaving your security boundary.
  4. Write the sanitized stream to your long-term store and let the raw stream expire on a short TTL.

This "sanitize-at-ingest" architecture — placed in a Logstash filter, a Fluent Bit output plugin, a Kafka stream processor, or a CloudWatch subscription Lambda — means the identifiers never reach long-term storage at all, which is dramatically stronger than retroactive cleanup. The log file PII scanning guide and the ETL and streaming pipeline guide walk through complete deployments for the major stacks.

Which Mask Mode for Which Log Consumer

  • Developers debugging: replace — placeholders like [IP_ADDRESS] keep lines readable and make it obvious what was removed.
  • Security analytics / rate limiting: hash — the same client always produces the same token, so counting, joining, and alerting still work without storing the address.
  • Third-party sharing or public postmortems: redact — remove the values entirely; placeholders can themselves leak structure you do not want to publish.

Code Examples

Sanitizing a Log File Before Archival (Python)

This script reads a raw access log in chunks, masks all network and device identifiers with consistent hashes, and writes the sanitized log for long-term retention:

import requests

API_URL = "https://piidetectionapi.com/api/moderate.php"
NETWORK_ENTITIES = ["IP_ADDRESS", "MAC_ADDRESS", "DEVICE_ID",
                    "IMEI", "COOKIE", "USER_AGENT"]
CHUNK_CHARS = 45000  # stay under the 50k request limit

def sanitize_chunk(chunk: str) -> str:
    resp = requests.post(API_URL, json={
        "api_key": "YOUR_API_KEY",
        "api_type": "pii_detection",
        "text": chunk,
        "entities": NETWORK_ENTITIES,
        "mask_mode": "hash",   # same IP -> same token, correlation preserved
    }, timeout=60)
    resp.raise_for_status()
    return resp.json()["anonymized_text"]

with open("access.log") as src, open("access.sanitized.log", "w") as dst:
    buffer = []
    size = 0
    for line in src:
        buffer.append(line)
        size += len(line)
        if size >= CHUNK_CHARS:
            dst.write(sanitize_chunk("".join(buffer)))
            buffer, size = [], 0
    if buffer:
        dst.write(sanitize_chunk("".join(buffer)))

Express Middleware to Scrub Identifiers From Support Tickets (JavaScript)

// Scrub network identifiers from ticket bodies before they are stored
async function scrubNetworkIdentifiers(req, res, next) {
  try {
    const resp = await fetch("https://piidetectionapi.com/api/moderate.php", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        api_key: process.env.PII_API_KEY,
        api_type: "pii_detection",
        text: req.body.ticketBody,
        entities: ["IP_ADDRESS", "MAC_ADDRESS", "IMEI", "COOKIE"],
        mask_mode: "replace",
        custom_instruction: "Do not flag private RFC 1918 IP ranges",
      }),
    });
    const data = await resp.json();
    req.body.ticketBody = data.anonymized_text;
    req.piiAudit = { found: data.entities_detected, ms: data.processing_time_ms };
    next();
  } catch (err) {
    next(err); // fail closed: do not store unscanned text on API failure
  }
}

Raising the Threshold for Noisy Version-String Data (cURL)

If you scan text dense with software version numbers, raise threshold so only high-confidence addresses survive:

curl -X POST https://piidetectionapi.com/api/moderate.php \
  -H "Content-Type: application/json" \
  -d '{
    "api_key": "YOUR_API_KEY",
    "api_type": "pii_detection",
    "text": "Upgraded agent to 7.2.1.4400; client 198.51.100.23 reconnected.",
    "entities": ["IP_ADDRESS"],
    "threshold": 0.8,
    "mask_mode": "replace"
  }'

Handling Edge Cases

Version Numbers and Dotted Numerics

Four-part version strings are the classic IPv4 false positive. The model resolves most through context — "released", "upgraded to", "SDK" push confidence down; "connected from", "client=", "src" push it up. For build-log-heavy corpora, combine a raised threshold with a custom_instruction such as "ignore software version numbers".

Documentation and Example Addresses

RFC 5737 reserves 192.0.2.0/24, 198.51.100.0/24, and 203.0.113.0/24 for documentation, and 2001:db8::/32 serves the same role for IPv6. These are detected like any other address — the API cannot know your text is documentation — so if you scan technical manuals, exclude them explicitly via custom_instruction.

Defanged Indicators in Security Reports

Threat-intelligence write-ups deliberately obfuscate addresses as 203[.]0[.]113[.]45 or hxxp://… to prevent accidental clicks. The detector recognizes common defanging conventions, which matters if your policy is to strip indicators before sharing reports externally — see the cybersecurity industry guide for the incident-response workflow.

Randomized MAC Addresses

Modern mobile operating systems randomize Wi-Fi MAC addresses per network, so a detected MAC may be ephemeral rather than a stable hardware identifier. Detection still flags it — a randomized MAC is stable per network and remains an identifier in that scope — but your retention policy may reasonably treat locally-administered MACs (second hex digit 2, 6, A, or E) differently.

Note: Offsets in the response are character positions into the exact string you submitted. If you pre-process logs (trimming, re-encoding), do the masking with anonymized_text from the same call rather than applying offsets to a different copy of the data.

Frequently Asked Questions

Does the API detect both IPv4 and IPv6 addresses?

Yes. Both families are returned under the IP_ADDRESS entity type, including compressed IPv6 notation, IPv4-mapped IPv6 forms, zone indices, bracketed address-plus-port forms, and CIDR notation. You do not need separate configuration for the two families.

Are internal/private IP addresses treated as PII?

They are detected by default, because internal addresses can identify employees and internal infrastructure exposure is itself a security concern. If your policy excludes them, add a custom_instruction such as "do not flag private RFC 1918 IP ranges" — no client-side filtering needed.

How do I keep the ability to correlate events after masking IPs?

Use mask_mode: "hash". Every occurrence of the same address maps to the same consistent token, so grouping, joining, and rate-limit analytics continue to work while the raw address is no longer stored. Note that consistent hashing is pseudonymization under GDPR, not anonymization — it reduces risk but keeps the data in scope.

Is a dynamic IP address really personal data under GDPR?

In most operational contexts, yes. The CJEU held in Breyer that a dynamic IP is personal data for a website operator because legal means exist to obtain the subscriber link from the ISP. Combined with the timestamps that logs always carry, treat logged client IPs as personal data unless your DPO documents otherwise.

Can I scan high-volume logs without blowing my request budget?

Yes — batch lines into chunks of up to 50,000 characters per request instead of scanning line by line. A single request can cover tens of thousands of short log lines. See pricing for volume tiers, and the on-premise deployment option if data cannot leave your environment.

What about user-agent strings — are they really identifying?

Alone, a common user agent is shared by millions of browsers. But an unusual UA, or any UA combined with an IP and timestamp, can fingerprint an individual browser with high precision — which is why CCPA lists "unique identifiers" and probabilistic identifiers explicitly. Detecting USER_AGENT lets you apply hashing so aggregate browser statistics survive without retaining the raw fingerprint.

Does detection work on languages other than English?

Yes. The identifiers themselves are language-neutral, and the surrounding-context model works across the 60+ languages the API supports, so a MAC address inside a German support ticket or a Japanese crash report is detected just as reliably. See the supported languages page.

Start Detecting Network Identifiers Today

Try the live demo on your own log data, or get an API key and sanitize your first file in minutes.

Try the Live Demo View Pricing