Format choice
Pro and Scale get the
ranges table: the VPN / proxy / hosting / CDN / Tor /
relay CIDR ranges. The points table, every residential-proxy exit IP as a
/32, needs Business in every format, CSV included.
MMDB is for local lookups: load the two files into memory once, and refresh
them daily.
Scheduling
The MMDB and Parquet files are rebuilt once a day, at no fixed time. The crontab below checks twice a day; pulling more often downloads the same files again. The MMDB ships as two files.artifact=ranges (the default) is
wxa_vpn.mmdb — the VPN / proxy / hosting / CDN / Tor / relay CIDR-ranges
layer. artifact=points is wxa_vpn-points.mmdb — the residential-proxy
per-IP (/32) layer. Download both for full coverage.
GET /export/mmdb does not return the database itself. It returns JSON with a
signed S3 download URL that expires after an hour:
download_url. Save this script as /usr/local/bin/wxa-vpn-refresh-mmdb
and make it executable (chmod +x). It needs curl and jq, and
/var/lib/wxa-vpn must exist and be writable by the user cron runs it as.
>> /var/lib/wxa-vpn/refresh.log 2>&1 to each entry.
Then schedule both layers. Cron does not read your shell profile, so set the
key in the crontab. Keep each entry on one line: cron does not continue a line
that ends in \.
MMDB lookup (Python)
For a complete verdict, check the points DB first (an exact /32 residential-proxy detection wins), then fall back to the ranges DB:None) means an unknown IP, not an error.
wxa_vpn.mmdb alone does NOT include the residential-proxy points — pull
wxa_vpn-points.mmdb for that layer.
Parquet to Snowflake
GET /export/parquet answers the same way as /export/mmdb: JSON whose
download_url points at the file (artifact=ranges, the default, or
artifact=points). Save the ranges file in your stage as
wxa_vpn_ranges.parquet, the name the COPY below reads; the download’s own
name carries the build date. Snowflake reads a Parquet file as one VARIANT
value per row, so the COPY selects each column out of it and casts it.
USE_LOGICAL_TYPE = TRUE makes Snowflake read first_seen and last_seen as
the UTC instants they are; without it they load as TIMESTAMP_NTZ, and the
cast to TIMESTAMP_TZ applies your session’s time zone to them:
A file with no rows declares the same double and timestamp columns, and every
other column as a string.
Until October 2026,
confidence, first_seen, last_seen and hits_days_pct
were strings in Parquet. A table that declares them as strings, such as an
Athena or Hive external table, a BigQuery table or a Spark schema, has to
declare them as double and timestamp before it reads a newer file.
A points file loads the same way, with its own columns. Load its two list
columns, providers_list and geo_targets_seen, into VARIANT columns.
Which window file to use
Each daily build also cuts the points table into four shorter files. Like every points file, they need Business or Enterprise.data_as_of is the time of the most recent observation in the build. It is in
the build’s manifest.json and on the Data as of line of its README. The
windows have no upper edge, so a row seen after data_as_of is in every window
file. Each window holds every row of the shorter ones: 1-day, then 7-day,
30-day, 90-day, and the full points file. All five have the same columns, so
one loader reads them all. GET /api/v1/export/dataset lists them, with
table set to points_1d, points_7d, points_30d, points_90d or
points; format=csv-zstd or format=parquet narrows the list. A build
without a data_as_of ships no window files: filter the full points file on
last_seen instead.
A shorter window holds fewer addresses that have stopped being proxy exits
since we saw them, and it leaves out exits we last saw before it starts. Pick
the file by what your rule does when it matches:
- 1-day file: for your strictest action, such as a block, where acting on an address that is no longer an exit costs more than missing one.
- 7-day file: for a step-up, such as a challenge or a review, where a sighting from earlier in the week is still worth acting on.
- 30-day file: for a softer response, such as a lower rate limit or a flag for later review, where a sighting from the last month is still worth noting.
- 90-day file: for lookbacks and investigations over the last quarter.
- Full points file: for older history, or to apply your own cut-off on
last_seenorfreshness_class. It also includesfrozenrecords, last seen more than 90 days ago.
File size
Approximate sizes of one daily build in October 2026; they change with every build.
Plan storage and bandwidth accordingly. The CSV files in the table are
gzip-compressed and Parquet compresses internally; the MMDB files download
uncompressed.