Multi-Site ANPR: Shared Plate Intelligence at Scale

Aug 16, 2026 · 14 min read

Why Single-Site ANPR Leaves Value on the Table

A standalone ANPR camera on a single forecourt or car park entrance is a useful tool. It records arrivals and departures, flags known plates and gives an operator a time-stamped audit trail. For a single location, that is often sufficient. The moment an operator runs two or more sites, however, the value of that data is being systematically wasted. A bilking vehicle flagged at one forecourt can drive straight into another site in the same group. A permit abuser banned from one car park can freely use the next one on the same estate. A logistics yard can see an asset leave but has no visibility of when or whether it arrived at the destination depot.

This is the gap that a multi-site ANPR architecture closes. By centralising plate events from distributed cameras into a single platform, operators gain cross-site intelligence: shared watchlists, real-time alerts routed to the right team, correlated vehicle journeys across locations and a unified compliance posture for data protection. For developers, building this on a REST number plate recognition API is considerably faster and cheaper than commissioning bespoke on-premise processing hardware at every site.

Common Multi-Site Use Cases

Before choosing an architecture, it pays to be precise about the business problem. Four patterns recur consistently across UK deployments.

Forecourt groups and fuel bilking. A drive-off at one petrol station in a group should immediately raise the risk level for every other station. Sharing a bilking watchlist means the cashier at a sister site sees a warning before the driver reaches the pump, not after they have refuelled and left.

Car park estates and permit abuse. Permit holders on a retail park or residential development are often tied to a specific car park. A vehicle issued a parking charge notice for overstaying at one location should be flaggable across the entire network. Without a shared ANPR watchlist, enforcement is easily circumvented by simply moving to the next car park.

Logistics networks and asset tracking. A haulage operator with multiple depots needs to know which trailers, HGVs or company vehicles have left which yard and when they are expected at, or have arrived at, the next. Cross-site journey correlation turns two independent gate reads into an end-to-end transit record with a calculated transit time and an automated alert if a vehicle is overdue.

Retail parks and dwell analytics. A retail park management company operating several parks in a region can correlate how often the same vehicle visits different sites, how long it dwells and whether its patterns match known loss-prevention profiles. This level of insight is only possible when all plate events flow into a single data store.

Architecture: Cloud API Versus On-Premise

Traditional multi-site ANPR deployments place a recognition server at each location. Each server runs its own software, maintains its own database and periodically syncs data via a scheduled job or VPN tunnel. The disadvantages at scale are significant: hardware refresh cycles, per-site software licences, fragmented watchlists that are perpetually slightly out of sync, and an engineering burden every time a new site is added.

An API-first cloud model inverts the architecture. Each site runs lightweight edge software, or uses the camera manufacturer's HTTP trigger, to capture a plate image and POST it to a central recognition endpoint. The intelligence lives in the cloud; the edge only needs to capture and transmit. Adding a new site means pointing another camera feed at the same API endpoint, not provisioning new server hardware. Watchlists, alert rules and retention policies are managed once, centrally, and take effect immediately across every site.

The NPR API exposes this pattern cleanly. A recognition request is a POST to https://nprapi.com/api/v1/recognise with the plate image sent as a multipart/form-data payload using a field named image. The API key goes in the X-API-Key header. The response is structured JSON containing the recognised registration, a confidence score as an integer from 0 to 100, and the number of credits consumed. That single integration point serves every site in the network.

Step 1: Normalising Plate Events Across Heterogeneous Sites

In practice, a network of sites rarely has identical camera hardware. You may have ANPR cameras from three different manufacturers, some triggering on motion, others firing HTTP callbacks on every vehicle pass. The first architectural task is to normalise all of these into a single canonical event schema before anything is written to your central database.

A minimal normalised event should contain: a unique event identifier; a site identifier (a short string or UUID you assign to each physical location); the timestamp in UTC ISO 8601 format; the raw registration string returned by the API; the confidence score; the direction of travel if your camera supports it (entry or exit); and the full API response object stored as a JSON blob for auditability. Adding a site_id field to every event is what makes cross-site queries possible downstream.

Your orchestration layer, a lightweight Node.js or Python service running per site or centrally for low-latency locations, receives the camera trigger, fetches the image, calls the recognise endpoint and writes the normalised event to your central store. This is the point at which heterogeneity ends. Downstream, everything is the same shape regardless of which camera produced the image.

Step 2: Building and Syncing a Shared Watchlist

A shared watchlist is a database table or collection containing registrations of interest, a severity level, an optional expiry timestamp and the sites to which the entry applies. The critical design decision is that the watchlist must be the single source of truth. Replicating it per site with manual sync jobs is exactly what allows a flagged vehicle to slip through during the lag window.

In a cloud API model, watchlist evaluation happens in your central orchestration service immediately after the recognition response is received. The flow is: camera triggers, orchestration layer calls the NPR API, receives the registration, queries the central watchlist, and if a match is found, fires an alert. Because the watchlist query happens in the same service that processes the API response, there is no sync delay. A plate added to the watchlist at 09:14 is live at every site by 09:14.

For large watchlists with high-frequency reads, keep the active watchlist in a fast in-memory store such as Redis, with the authoritative copy in your relational database. On any watchlist write, invalidate and reload the cache. This keeps lookup latency in the low single-digit milliseconds even when the watchlist contains tens of thousands of entries.

Step 3: Routing Alerts to the Right Team via Webhooks

A multi-site platform serves multiple operations teams. The forecourt manager at Site A does not need to see alerts from Sites B through F. A central security desk may need to see alerts from all sites, but only above a certain severity. Routing logic must be a first-class concern, not an afterthought.

Webhooks are the right mechanism here. When your orchestration layer confirms a watchlist match, it publishes a structured event payload to each registered webhook endpoint for that site. The payload should include the site identifier, the registration, the confidence score, the timestamp, the watchlist entry that was matched and any enrichment data such as vehicle make, model and colour. Each operations team configures its own receiving endpoint, whether that is a Slack channel, a security desk dashboard or a forecourt point-of-sale terminal.

Design your webhook dispatcher with a durable queue behind it. If a downstream endpoint is temporarily unavailable, the event must not be lost. Use exponential backoff with jitter for retries, and route persistently failing deliveries to a dead-letter queue for manual review. Log every delivery attempt with the HTTP response code, latency and retry count so that problems are visible before they become incidents.

Step 4: Cross-Site Journey Correlation

Journey correlation is what transforms a collection of independent plate reads into a network-level intelligence layer. The concept is straightforward: when the same registration appears as an exit event at one site and an entry event at another site within a plausible time window, you have a transit record.

Consider a logistics network with depots at Birmingham, Coventry and Leicester. A trailer leaves Birmingham at 07:42 and is expected at Coventry by 09:00. Your correlation service queries: for each exit event at the Birmingham site in the last two hours, is there a corresponding entry event at any downstream site? If the trailer arrives at Coventry at 08:51, the transit record is created automatically and the expected arrival is marked complete. If 09:15 passes without an entry event at any downstream site, an alert fires to the fleet controller.

Implement this as a scheduled or streaming job that runs over your central events table. The query joins exit events and entry events on the registration field, filters by site pairs that have a defined transit relationship and applies a configurable time window. Store the resulting journey records as a separate entity in your database. The NPR API's multiple=true flag, which returns a plates array with per-plate registration, confidence and country code, is particularly useful at high-throughput gate points where more than one vehicle may appear in a wide-angle frame.

Step 5: Enriching Plate Events with Vehicle Data

A raw registration string tells you that a specific vehicle was at a specific location. Adding vehicle data, make, model and colour, gives operational teams the context they need to act. A watchlist alert for a blue Ford Transit is far more actionable than a registration string alone, particularly in a busy logistics yard or a retail park with limited radio communications.

The NPR API provides this enrichment in a single call by adding vehicle=true as a form field or query parameter on the recognise request. When set, the response includes make, model and colour data alongside the plate read, with no separate lookup step and no additional integration to maintain. At scale, this means every plate event in your central database is automatically enriched at read time.

For a multi-site car park estate where enforcement officers cover several locations, the vehicle description visible on their mobile dashboard can prevent misidentification. For a forecourt group sharing a bilking watchlist, the colour and model confirm a match before staff intervention. Adding scene=true to the same call can further enrich the event with scene intelligence, useful where camera placement captures wider context beyond the plate itself.

Handling UK GDPR Across Multiple Sites

Vehicle registration marks are treated as personal data by the ICO when processed by an ANPR operator, because they can be combined with other information to identify an individual. The ICO's guidance on video surveillance, which explicitly covers ANPR, is currently under review following the Data (Use and Access) Act, so operators should monitor the ICO website for updated guidance. The core obligations remain: data must be adequate, relevant and limited to what is necessary for the stated purpose, and a Data Protection Impact Assessment should address the entire platform, not just individual sites.

The complexity in a multi-site deployment is that different sites may operate under different lawful bases and different retention requirements. A forecourt retaining plate reads to investigate drive-offs may justify a longer retention period than a retail car park where the purpose is simply managing dwell time. A security deployment may have a contractual or legitimate interest basis that differs from a standard parking operation.

A cloud API model handles this cleanly. Each site identifier in your central events table carries a retention policy configuration. A nightly job evaluates each event against the policy for its site and deletes or anonymises records that have exceeded their retention window. Because the policy is data rather than code, changing the retention period for a site requires a database update, not a deployment. Where a site requires zero retention processing, for example where a plate read is used only for an access control decision with no persistent record, your orchestration layer can call the recognition endpoint, evaluate the result and discard the response without writing to the events table at all.

As the platform operator, you are likely a data controller for the central events store. Reflect any joint controller arrangements in your contracts with site operators, and ensure data sharing agreements are in place before plate data crosses organisational boundaries.

Confidence Scores and Error Handling in Production

The NPR API returns confidence as an integer from 0 to 100. In a single-site deployment, a simple threshold, for example accepting reads above 85 and flagging reads between 70 and 85 for manual review, is workable. In a multi-site production environment, the right threshold may vary by site based on camera quality, lighting conditions and typical vehicle speed at the gate point.

Store the raw confidence score on every event. Do not discard low-confidence reads; instead, route them to a review queue where a human operator can confirm or correct the plate before the event is used for watchlist evaluation or journey correlation. Acting on a low-confidence read risks both false alerts and missed genuine matches, neither of which is acceptable in an operational system.

Build explicit error handling for API call failures. If the recognition endpoint returns a non-200 response, log the failure with the raw image reference, queue the retry with exponential backoff and do not silently drop the event. In a high-security or high-value deployment, a gap in the event stream is operationally significant and should trigger a monitoring alert in its own right.

Performance and Rate Limits at Scale

Multi-site ANPR networks have predictable traffic spikes. A logistics network sees a burst of gate reads at shift changes, typically around 06:00 and 14:00. A retail park sees its peak during weekend midday hours. A forecourt group may see synchronised spikes across sites during morning and evening rush hours. Your integration must handle these bursts without dropping events or introducing unacceptable latency.

Place a message queue between your camera triggers and your API call workers. When a burst arrives, the queue absorbs it and the workers process at a steady rate within your API plan's rate limits. Size your worker pool based on your peak site count multiplied by your maximum events per minute per site, with a headroom buffer of at least 30 per cent. For very large bursts, the NPR API's batch endpoint at https://nprapi.com/api/v1/batch accepts multiple images in a single request and returns a job UUID whose status you poll via GET https://nprapi.com/api/v1/batch/{uuid}, reducing the number of individual API calls during peak periods.

Monitor your credit consumption per site. In a large estate, a single misconfigured camera polling at high frequency can consume a disproportionate share of your credit allocation. Set per-site consumption alerts in your monitoring layer so that anomalies are caught early, before they affect other sites on the same plan.

Sample Orchestration Code

The following Python example shows a minimal orchestration function that receives a plate image path and site identifier, calls the NPR API, evaluates a shared watchlist in Redis and fires a webhook if a match is found.


import requests
import redis
import httpx

NPR_API_URL = "https://nprapi.com/api/v1/recognise"
NPR_API_KEY = "your-api-key-here"
CONFIDENCE_THRESHOLD = 85

redis_client = redis.Redis(host="localhost", port=6379, db=0, decode_responses=True)


def process_plate_event(image_path: str, site_id: str) -> dict:
    """
    Call the NPR API, evaluate the watchlist and fire a webhook on a match.
    Returns the normalised event dict.
    """
    with open(image_path, "rb") as f:
        response = requests.post(
            NPR_API_URL,
            headers={"X-API-Key": NPR_API_KEY},
            files={"image": f},
            data={"vehicle": "true"}
        )

    response.raise_for_status()
    result = response.json()

    if not result.get("success"):
        raise ValueError(f"Recognition failed for site {site_id}")

    registration = result["registration"]
    confidence = result["confidence"]
    credits_used = result["credits_used"]

    event = {
        "site_id": site_id,
        "registration": registration,
        "confidence": confidence,
        "credits_used": credits_used,
        "vehicle": result.get("vehicle", {}),
    }

    if confidence >= CONFIDENCE_THRESHOLD:
        check_watchlist_and_alert(event)

    return event


def check_watchlist_and_alert(event: dict) -> None:
    """
    Check the shared watchlist in Redis and POST a webhook if matched.
    """
    registration = event["registration"]
    watchlist_entry = redis_client.hgetall(f"watchlist:{registration}")

    if not watchlist_entry:
        return

    sites_scope = watchlist_entry.get("sites", "all")
    if sites_scope != "all" and event["site_id"] not in sites_scope.split(","):
        return

    webhook_url = redis_client.get(f"webhook:{event['site_id']}")
    if not webhook_url:
        return

    payload = {
        "event_type": "watchlist_match",
        "site_id": event["site_id"],
        "registration": registration,
        "confidence": event["confidence"],
        "vehicle": event.get("vehicle", {}),
        "watchlist_reason": watchlist_entry.get("reason", ""),
        "severity": watchlist_entry.get("severity", "medium"),
    }

    try:
        httpx.post(webhook_url, json=payload, timeout=5.0)
    except httpx.RequestError as exc:
        # In production, push to a retry queue rather than logging and continuing
        print(f"Webhook delivery failed for {event['site_id']}: {exc}")

This is intentionally minimal. In production you would replace the direct httpx.post call with a durable queue-backed dispatcher, add idempotency keys to every event, persist each event to your database before evaluating the watchlist, and wrap the entire function in structured logging. The pattern, however, is the complete loop: image in, structured JSON out, watchlist check, webhook fire.

Where to Start and How to Scale

A multi-site ANPR system built on a REST number plate recognition API is an integration project, not a complex infrastructure undertaking. The recognition intelligence is provided by the API. Your job as a developer is to normalise events from heterogeneous cameras into a consistent schema, maintain a shared watchlist with low-latency lookup, route alerts to the right teams via reliable webhooks, correlate journeys across site pairs, enrich events with vehicle data at read time and enforce per-site retention policies from a single configuration layer.

Start with two sites and a real operational use case. Stand up the orchestration layer, connect both camera feeds, write events to a shared database and implement the watchlist check. Once that loop is working reliably, adding a third and fourth site is a configuration change rather than an engineering project. Use the NPR API to develop and test the integration at low volume, then scale your plan as the site count grows. The architecture described here applies equally to forecourt groups, parking estates, logistics networks and retail parks. The pattern is the same in every case: a single API endpoint, a canonical event schema and shared intelligence applied consistently at every point in the network.

Ready to integrate number plate recognition?

Get Started Free