FCC ULS License Scraper - Business Radio & Microwave Licenses
Pricing
from $2.10 / 1,000 licenses
FCC ULS License Scraper - Business Radio & Microwave Licenses
Scrape FCC Universal Licensing System (ULS) business/industrial land-mobile radio (IG, YG) and point-to-point microwave (CF, MG) licenses by state, status, and expiration window from FCC bulk files.
Pricing
from $2.10 / 1,000 licenses
Rating
0.0
(0)
Developer
Groundplane Labs
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 days ago
Last modified
Categories
Share
Scrape commercial land-mobile business radio (IG, YG, GJ, YO, YB, YI, etc.) and point-to-point microwave (CF, MG, NN, TP, etc.) licenses directly from the Federal Communications Commission (FCC) Universal Licensing System (ULS) weekly bulk license archives (l_LMpriv.zip and l_micro.zip). Filter by radio service code, licensee state, license status, or upcoming expiration window to identify organizations operating commercial radio and microwave infrastructure.
Disclaimer: This Actor is an independent tool and is not affiliated with or endorsed by the Federal Communications Commission (FCC).
What it does
- Streams FCC ULS Bulk Archives via HTTP Range Requests: Queries the official FCC ULS complete license archives (
l_LMpriv.zipandl_micro.zipondata.fcc.gov) using ZIP Central Directory HTTPRangerequests to stream and decompress only the License Header (HD.dat) and Entity (EN.dat) tables. - Commercial Business Radio & Microwave Coverage: Supports Private Land Mobile Industrial/Business Pool (
IG,YG,YB,YI,YO,GJ,GO, etc.) and Microwave (CF,MG,NN,TP, etc.) radio service codes. - Expiring License Detection: In
EXPIRINGmode, filters active (A) licenses expiring between today andtoday + expiringWithinDays(default 180 days) and calculates exactdaysUntilExpiration. - Privacy Controls Built In: Individual licensees are excluded by default: any row with
applicant_type_code == 'I'is individual unconditionally, a row whose entity name is inLAST, FIRSTform built from its last/first name fields is individual, a row with a personal first/last name and no business entity name is individual, and a partnership (applicant_type_code == 'P') row whose entity name has no business marker (such as LLC, LP, LLP, INC, CO, or CORP) is filtered the same way. Contact fields (contactName,contactEmail,contactPhone) are also excluded by default (includeIndividualLicensees: false,includeContacts: false). - Actionable Ordering: In
EXPIRINGmode, results are sorted byexpirationDateascending (soonest expiring first) so urgent renewals appear first; in all other modes (ACTIVE,EXPIRED,CANCELLED), results are sorted bygrantDatedescending (newest first) before applyingmaxItems.
Who it's for
- Two-Way Radio & Land Mobile Dealers: Find commercial facilities, farms, warehouses, construction firms, hotels, utilities, and school districts whose FCC Part 90 business radio (
IG/YG) licenses are approaching their 10-year renewal window. - Telecom & Backhaul Providers: Track common carrier (
CF) and private operational fixed (MG) point-to-point microwave links by state and expiration date. - FCC Licensing & Compliance Consultants: Monitor upcoming license expirations and recently cancelled or expired licenses requiring renewal or re-coordination.
- Infrastructure & M&A Analysts: Audit active spectrum holdings and wireless infrastructure footprints across corporate entities (by FRN and call sign).
Input
All parameters have working defaults/prefills that return results in under 2 minutes.
| Field | Type | Default / Prefill | Description |
|---|---|---|---|
radioServiceCodes | array<string> | ["IG", "YG"] | FCC ULS radio service codes. Land Mobile uses l_LMpriv.zip (IG, YG, YB, YI, YO, GJ, GO, etc.); Microwave uses l_micro.zip (CF, MG, NN, TP, etc.). |
states | array<string> | ["AZ"] | Two-letter US state or territory postal codes for the licensee address (e.g. ["AZ"], ["AZ", "NV"]). Leave empty for all states. |
status | string | "EXPIRING" | EXPIRING (Active licenses expiring within expiringWithinDays), ACTIVE, EXPIRED, or CANCELLED (includes Cancelled C and Terminated T). |
expiringWithinDays | integer | 180 | Lookahead window in days when status is "EXPIRING". |
includeContacts | boolean | false | Include a named attention contact, email, and telephone number (contactName, contactEmail, contactPhone) from EN.dat. Defaults to false for privacy compliance. |
includeIndividualLicensees | boolean | false | Include licenses held by natural persons. A licensee is a natural person when applicant_type_code == 'I' (unconditionally), when EN.dat has a first/last name and no business entity name, or when the entity name is in LAST, FIRST form. Partnership rows (applicant_type_code == 'P') with no business marker in the entity name are treated the same way. Defaults to false so only organizational/business licensees are returned. |
maxItems | integer | 200 | Maximum number of license records to output. |
Example input JSON
{"radioServiceCodes": ["IG", "YG"],"states": ["AZ"],"status": "EXPIRING","expiringWithinDays": 180,"includeContacts": false,"includeIndividualLicensees": false,"maxItems": 200}
Example run options (with default $50 max charge protection)
When invoking via the Apify API or CLI, set a default maximum charge of $50 ("maxTotalChargeUsd": 50):
{"maxTotalChargeUsd": 50}
The Actor checks calculate_max_event_charge_count_within_limit("apify-default-dataset-item") before every dataset push and stops cleanly when your spending limit is reached.
Output
Results are saved to the default dataset. Deduplication is enforced by callSign + uniqueSystemId.
Output fields
| Field | Type | Description |
|---|---|---|
callSign | string | FCC license call sign (HD.dat column 5). |
uniqueSystemId | string | FCC ULS unique_system_identifier (HD.dat column 2). |
frn | string | null | 10-digit FCC Registration Number (FRN). |
licenseeName | string | null | Business or institutional licensee name (EN.dat entity name). |
radioService | string | 2-letter FCC radio service code (e.g. IG, YG, CF, MG). |
licenseStatus | string | Normalized status: Active, Expired, Cancelled, or Terminated. |
grantDate | string | null | License grant date in YYYY-MM-DD format. |
expirationDate | string | null | License expiration date in YYYY-MM-DD format. |
daysUntilExpiration | integer | null | Calendar days from today (UTC) until expirationDate (negative if already expired). |
street | string | null | Licensee street address or P.O. Box. |
city | string | null | Licensee city. |
state | string | null | Two-letter state or territory code. |
zip | string | null | Licensee postal ZIP code (formatted XXXXX or XXXXX-XXXX). |
ulsUrl | string | Direct link to the FCC ULS license page (https://wireless2.fcc.gov/UlsApp/UlsSearch/license.jsp?licKey=<uniqueSystemId>). |
contactName | string | null | Included only when includeContacts is true. |
contactEmail | string | null | Included only when includeContacts is true. |
contactPhone | string | null | Included only when includeContacts is true. |
Sample output row (synthetic example)
{"callSign": "WQXM901","uniqueSystemId": "3891042","frn": "0025918402","licenseeName": "DESERT RIDGE LOGISTICS LLC","radioService": "IG","licenseStatus": "Active","grantDate": "2016-11-18","expirationDate": "2026-11-18","daysUntilExpiration": 18,"street": "4200 W BUCKEYE RD","city": "PHOENIX","state": "AZ","zip": "85009","ulsUrl": "https://wireless2.fcc.gov/UlsApp/UlsSearch/license.jsp?licKey=3891042"}
(If includeContacts: true is enabled, optional contact fields "contactName": "FLEET OPERATIONS DEPT", "contactEmail": "radio-compliance@example.com", and "contactPhone": "602-555-0199" are also included.)
How pricing works
Pay per result. You only pay for rows returned.
Data source and terms
- Official Source: Federal Communications Commission (FCC) — Universal Licensing System (ULS) Public Access Files / Database Downloads
- Bulk Archive Endpoints:
- Private Land Mobile (
l_LMpriv.zip):https://data.fcc.gov/download/pub/uls/complete/l_LMpriv.zip - Microwave (
l_micro.zip):https://data.fcc.gov/download/pub/uls/complete/l_micro.zip
- Private Land Mobile (
- Update Cadence: Complete license archives are generated weekly (typically Sunday morning) by the FCC.
- Terms of Use: FCC ULS public access files are U.S. Government public records published under FCC Privacy & Data Policy.
Compliance
This Actor retrieves public licensing records published by the Federal Communications Commission (FCC). Personal contact fields (includeContacts and includeIndividualLicensees) are turned off by default.
If you enable contact fields or use organization address data for outreach:
- Regulatory Compliance: Buyers are solely responsible for complying with the Telephone Consumer Protection Act (TCPA), the National Do-Not-Call (DNC) Registry, the CAN-SPAM Act, and all applicable state and international privacy and telemarketing laws before conducting any outreach.
- No Consumer / Individual Targeting: This tool is designed for B2B commercial infrastructure research (e.g., corporate, industrial, utility, and institutional radio licensees) and must not be used for consumer or individual targeting.
Limits and FAQ
- Why does the Actor use 1 GB memory (
1024 MB)? The FCC's complete Land Mobile Private archive (l_LMpriv.zip) is ~424 MB compressed (~2.5 GB uncompressed across all tables). This Actor uses HTTPRangerequests against the ZIP Central Directory to stream and decompress onlyHD.dat(~26.7 MB compressed) andEN.dat(~75.3 MB compressed) in 256 KB chunks, filtering rows in memory in ~14 seconds. If a network intermediary ignoresRangerequests, the Actor downloads the full archive once and extracts the same two tables locally rather than misreading offsets. Measured peak memory on the worst case (all states,ACTIVE,IG+YG+CF+MG) is about 616 MB, so 1024 MB is enough even when querying multiple states and both Land Mobile and Microwave archives in a single run. - Why does the Actor keep the stock
python-httpxUser-Agent? Documented exception:data.fcc.govis Akamai-fronted. Retested 2026-11-01 via httpx, the identified neutral UAGroundplaneLabs-Apify/1.0(no email) passes GETRangerequests (206) but fails HEAD requests (403 on every trial), and this Actor relies on HEAD to inspect each archive. The stock library UA passes both HEAD (200) and GETRange(206) and does not impersonate a browser, so it is kept deliberately. - What happens when 0 rows match?
Zero matches on a healthy source is a successful run: the status reads
Complete: 0 licenses matched your filtersand states how many records were scanned, plus which filters (states,expiringWithinDays,status, orradioServiceCodes) to widen. A run only fails loudly when the source itself is broken (empty or restructured files, failed downloads), so upstream data changes never fail silently. - Can I query both Land Mobile (
IG,YG) and Microwave (CF,MG) in one run? Yes. The Actor automatically maps each requested radio service code tol_LMpriv.ziporl_micro.zipand downloads only the required archive(s).
Troubleshooting
- Canary input: to smoke-test the Actor, run the default input above with
"maxItems": 5. It returns rows in well under a minute on a healthy source and ends with aComplete:status. - Status starts with
PARTIAL:: the run finished but something material was withheld, and the status message says exactly why (for example a stale weekly archive, a failed source archive, or rows skipped by validation). Rows already collected are still delivered. - Status starts with
Complete: 0 licenses matched: the source is healthy and records were scanned, but no license fits your filters. WidenexpiringWithinDays, addstatesorradioServiceCodes, or switchstatustoACTIVE. - Run failed with a layout or download message: the FCC changed or failed to publish a bulk file. Retry once; if it persists, report it as below.
Found a problem or need a field? Open an issue on the Issues tab; we respond quickly.
Changelog
v0.1.3 (2026-11-01)
- Privacy fix (Blocker):
applicant_type_code == 'I'rows are now individual unconditionally, entity names inLAST, FIRSTform are treated as individual, and partnership (P) rows with no business marker in the entity name are filtered by default. Added a unit test for the individual test. - Retry policy aligned to the fleet standard: 6 tries, jittered backoff from 2 to 32 seconds capped at 120 seconds, with
Retry-Afterhonored as seconds or as an HTTP date. - Default memory reduced from 4096 MB to 1024 MB (measured worst case about 616 MB). Strict boolean parsing for
includeContactsandincludeIndividualLicensees. Non-US state codes are pre-filtered and counted as filtered instead of failing validation. Listing wording uses singular contact naming and the description starts with "Scrape". User-Agent: the identified neutral UA was retested via httpx and fails HEAD, so the stock UA is kept as a documented exception (see Limits and FAQ).
v0.1.2 (2026-10-31)
- Red Team fix round (download integrity): the ZIP central-directory CRC32 is now carried through the download path; every 206 response has its Content-Range verified against the requested range; and decompression verifies the end-of-stream marker, the decompressed byte count, and the CRC32 against the central directory, so a truncated or corrupted stream fails loudly instead of yielding a partial table.
v0.1.1 (2026-10-31)
- Fixed run status contract: runs now end with
Complete:orPARTIAL:with honest scanned / matched / emitted counts; zero matches on a healthy source is aComplete: 0success instead of a failure. - Added per-row output validation before push and a core-column sentinel on
HD.dat/EN.datthat fails loudly if the FCC restructures the files. - Added per-archive isolation (one failed archive no longer discards the other's rows), a staleness check on the weekly archives, and a full-download fallback when a network intermediary ignores HTTP
Rangerequests. - Store categories corrected to Business only; default run options now include the $50 max charge; an explicit empty
stateslist now means all states, as documented.
v0.1 (2026-10-31)
- Initial release supporting FCC ULS Land Mobile Private (
l_LMpriv.zip) and Microwave (l_micro.zip) bulk archives via HTTP Range streaming. - Added
EXPIRING,ACTIVE,EXPIRED, andCANCELLEDfiltering, state filtering, and privacy-first contact flags (includeContacts,includeIndividualLicenseesdefaultfalse).