I built this actor; it's a paid tool on Apify with a free trial credit.
Every ocean shipment into the United States leaves a public record: the bill of lading names the US consignee, the overseas shipper, the goods, the weight and the ports. ImportYeti indexes those records into company pages, which is why it is the first stop for anyone asking "who imports solar panels into the US?" or "who makes Lululemon's leggings?". Freight forwarders use it to find prospects, suppliers use it to find buyers, sourcing teams use it to find factories with a track record.
The site has no export and no API. I'm an 18-year-old engineering student, and I built ImportYeti Scraper to turn keyword searches and company pages into clean rows. This post covers how it works, calling it from Python and Node, what a row looks like, and a small project: a ranked prospect list of active importers.
How it works
Two sources. The search box on the site calls a JSON endpoint (/api/search?q=...) that returns ten companies or suppliers per page with name, address, country, total shipments and the date of the most recent one. Each company page is a React Server Components page: the data arrives in self.__next_f.push([...]) chunks, so instead of a DOM parser the actor decodes those chunks and brace-matches the JSON objects out of them. The report object holds the supplier table (vendor_table), the HS code tree, the origin-country graph, the carriers with year-on-year change, the port-to-port lanes and the monthly series.
Things that cost real time and are worth knowing if you try this yourself:
- Requests are counted per IP. Every API answer carries
requestLimitRemaining, and it starts around 25. The actor uses Apify's datacenter proxy with a fresh IP every few requests and pauses on rate-limit answers, so a 1,000-company run gets through; from a single home IP you get throttled fast. - Two date formats on one page. The search API and the report tables print day/month/year (
25/07/2026); the report header prints month/day/year (10/19/2026). When one part is above 12 the order is obvious; otherwise you need to know which source you are reading. The actor normalises everything toYYYY-MM-DD. - The monthly series is in a separate chunk. The report object only holds a
$36:props:datareference; the real{"01/01/2015": {shipments, weight, teu}}map lives in the chart component's props. Easy to miss, and it is whereshipmentsByYearcomes from. - Contact details are masked (
XXX-XXX-X124), and I left them out on purpose: the actor stores company-level data only.
The HTML search page (/search?q=) is disallowed in ImportYeti's robots.txt and is never requested; the actor only reads the JSON endpoint and the company and supplier pages.
Python example
pip install apify-client from apify_client import ApifyClient client = ApifyClient("<YOUR_APIFY_TOKEN>") run = client.actor("rel8ble/importyeti-scraper").call(run_input={ "queries": ["solar panels"], "entityType": "company", # US importers only "minShipments": 5, "activeSinceYear": 2025, "maxItemsPerQuery": 100, }) for c in client.dataset(run["defaultDatasetId"]).iterate_items(): top = c["topSuppliers"][0]["name"] if c.get("topSuppliers") else "-" print(f'{c["totalShipments"]:>6} shipments | {c["shipments12m"]:>4} last 12m | {c["name"]:40} | {c.get("region") or "-":15} | top supplier: {top}') call() waits for the run to finish. With details on, each result is one report page, so 100 importers take about a minute at the default two parallel requests.
Node example
npm install apify-client import { ApifyClient } from 'apify-client'; const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' }); const run = await client.actor('rel8ble/importyeti-scraper').call({ startUrls: ['https://www.importyeti.com/company/lululemon-usa'], }); const { items } = await client.dataset(run.defaultDatasetId).listItems(); const c = items[0]; console.log(c.name, c.totalShipments, 'shipments;', c.shipments12m, 'in the last 12 months'); for (const s of c.topSuppliers.slice(0, 5)) console.log(' ', s.shipments, s.country, s.name, '|', s.hsCodes.join(', ')); What a row looks like
A real row from a run on 2026-10-21 (query yoga mats, an Indian supplier; lists shortened):
{ "name": "Travancore Mats And Matting", "type": "supplier", "url": "https://www.importyeti.com/supplier/travancore-mats-and-matting", "address": "Private Limited P B 5 1/206 Shaktheeswaram Junction Cherthala P O Cherthala Alappuzha Kerala 688524", "region": "State of Kerala", "country": "India", "countryCode": "IN", "totalShipments": 1243, "shipments12m": 206, "firstShipment": "2021-03-26", "lastShipment": "2026-10-15", "avgTeuPerMonth": 36.39, "estimatedShippingCostUsd": 2484434, "quarterlyGrowthPercent": -41.82, "topProducts": [{ "hsChapter": "57", "description": "Carpets", "shipments": 914 }], "topCustomers": [ { "name": "Ikea Supply", "type": "company", "countryCode": "US", "shipments": 1110, "shipments12m": 155, "teu": 2367, "hsCodes": ["5705.00", "9403.50"], "productDescriptions": "Jute Basket Matting Rugs Handwov Coir Matting ...", "url": "https://www.importyeti.com/company/ikea-supply" } ], "originCountries": [{ "country": "India", "continent": "Asia", "shipments": 1239 }], "carriers": [{ "scac": "MEDU", "name": "Msc Mediterranean Shipping Company", "shipments": 572, "shipments12m": 78, "yoyPercent": -45.07 }], "tradeLanes": [{ "loadingPort": "Colombo Harbor", "loadingCountry": "Sri Lanka", "unloadingPort": "Baltimore, Md.", "shipments": 118, "teu": 251 }], "shipmentsByYear": [{ "year": "2024", "shipments": 322, "teu": 707 }, { "year": "2025", "shipments": 285, "teu": 620 }], "databaseUpdated": "2026-10-19", "sourceQuery": "yoga mats" } A US importer row has the same shape with type: "company", a city and region, a website where ImportYeti knows one, and topSuppliers instead of topCustomers.
Small project: a ranked prospect list
Say you sell ocean freight and want the US companies that import lithium batteries, ranked by what they shipped in the last twelve months, with their current carrier so the call has something to say.
import csv from apify_client import ApifyClient client = ApifyClient("<YOUR_APIFY_TOKEN>") run = client.actor("rel8ble/importyeti-scraper").call(run_input={ "queries": ["lithium batteries", "lithium ion battery"], "entityType": "company", "minShipments": 10, "activeSinceYear": 2025, "maxItemsPerQuery": 300, }) rows = list(client.dataset(run["defaultDatasetId"]).iterate_items()) rows.sort(key=lambda c: c.get("shipments12m") or 0, reverse=True) with open("battery_importers.csv", "w", newline="", encoding="utf-8") as f: w = csv.writer(f) w.writerow(["company", "state", "website", "shipments_12m", "total_shipments", "teu_per_month", "top_carrier", "top_origin", "top_supplier", "importyeti"]) for c in rows: w.writerow([ c["name"], c.get("region"), c.get("website"), c.get("shipments12m"), c.get("totalShipments"), c.get("avgTeuPerMonth"), c["carriers"][0]["name"] if c.get("carriers") else "", c["originCountries"][0]["country"] if c.get("originCountries") else "", c["topSuppliers"][0]["name"] if c.get("topSuppliers") else "", c["url"], ]) print(f"{len(rows)} active importers saved to battery_importers.csv") Two queries, up to 600 rows with full reports, is about $0.17 at $0.29 per 1,000 results. The filters (minShipments, activeSinceYear) run on the search rows before any report is fetched, so one-off importers never cost anything.
Price and limits
- $0.29 per 1,000 results, no start fee; results removed by your filters and failed requests are free.
- Search is ImportYeti's: a keyword matches company names and product descriptions the way the site does. Use product words and synonyms, not categories.
- Per-IP rate limit: keep the Apify proxy on and
maxConcurrencyat 2; a 1,000-company run takes 10-15 minutes. - Sea freight only, US imports only; that is what the public bill-of-lading data covers.
- Top 25 suppliers, HS codes, countries, carriers and lanes per row;
partnerCountgives the full number. - No contact details, ever.
Questions or broken fields: the Issues tab on the actor page comes straight to me.
This article was drafted with AI and published by me.
Need a custom scraper or a ready dataset? Hire me on Fiverr: https://www.fiverr.com/rel8ble


