The 64 export columns, explained
Every column in the file, in the order it appears, what it contains and when it is empty — plus the file format itself, which is stranger than the extension suggests. This is the contract.
Every export has the same 64 columns in the same order, whatever the plan, the country or the category. All 64 are on every plan including the trial — columns are not something a tier withholds. If you exclude columns they are removed, but the survivors keep this order. Code that reads by header name will keep working; code that reads by index will too, provided you did not change the selection between runs.
The headers are not ours. They are scrap.io's header row, reproduced exactly, so a spreadsheet or an importer built against their export reads ours without a change.
64 columns, but only 34 things to tick
The column picker does not offer 64 checkboxes. It offers 34 groups, and eight of them produce more than one column. This is the one thing that surprises people building against the export: ticking Address gives you eleven columns, ticking All emails gives you nine, and ticking Contact pages gives you six.
| Group | Columns |
|---|---|
name | 1 — Name |
main_type | 1 — Main type |
all_types | 1 — All types |
google_id | 1 — Google ID |
link | 1 — Link |
phone | 3 — Phone, Phone international, Phone type |
email | 1 — Email |
website | 2 — Website, Website (root url) |
location_address | 11 — Full address through Country code |
location_coordinates | 2 — Longitude, Latitude |
timezone | 1 — Timezone |
reviews | 2 — Reviews rating, Reviews count |
is_closed | 1 — Is closed permanently |
working_hours | 1 — Working hours |
facebook_link | 1 |
youtube_link | 1 |
instagram_link | 1 |
linkedin_link | 1 |
twitter_link | 1 |
tiktok_link | 1 |
website_title | 1 — Website title |
website_meta | 3 — meta description, image, generator |
website_lang | 1 — Website lang |
contact_pages | 6 — Contact page 1–5 and All contact pages |
all_emails | 9 — the role-split set plus All emails |
all_facebook_links | 1 |
all_youtube_links | 1 |
all_twitter_links | 1 |
all_instagram_links | 1 |
all_linkedin_links | 1 |
all_tiktok_links | 1 |
website_technologies | 1 — Website technologies |
website_ad_pixels | 1 — Website ad pixels |
first_seen_at | 1 — First seen on |
That is the whole of the arithmetic. Eight groups write more than one column and produce
38 between them — 3 + 2 + 11 + 2 + 2 + 3 + 6 + 9. The other twenty-six write
one column each. 38 + 26 = 64. Over the API the group name is what you put in
exported_columns, never the header text —
creating exports over the API.
A column being in the file is not a promise that it is filled
The header row is always all 64. What arrives underneath depends on where the value comes from. Columns read from the map listing — name, types, Google ID, link, address, coordinates, timezone, reviews, closed status, working hours, first seen — are populated wherever the map publishes them. The columns read from the business's own website — the role-split email set, the contact pages, the website title, meta and language fields, technologies and ad pixels — depend on that website having been crawled, and that enrichment is still being rolled out. Until it reaches your rows those columns are written empty. Export a small batch and look at the file before you build a workflow on one of them. What each is for, once it lands, is in the enrichment columns.
Identity and the map listing
| Column | Contains | Empty when |
|---|---|---|
Name | The business name as it appears on the map listing | Never |
Main type | The primary category, e.g. Accountant | Rarely |
All types | Every category on the listing, comma-separated: Accountant,Accounting firm,Consultant | The listing has only one type |
Google ID | The Google feature id, 0x{hex}:0x{hex} — this is the primary key for the row and the identifier to quote to us | Never |
Link | A URL straight to the map listing, so any row can be checked by eye in one click | Never |
First seen on | When the business first entered our index, written Saturday, August 28, 2021 12:31 PM | Never |
First seen on is a full-text date, not ISO-8601, because that is the format the
header contract fixes. Parse it with a format string rather than a generic date parser.
Location — eleven columns from one tick, plus two coordinates
| Column | Contains | Empty when |
|---|---|---|
Full address | The whole address as published — and it starts with the business name: Norus Regnskapsbyrå AS, Hasleveien 28A, 0571 Oslo, Norway | Service-area businesses with no premises |
Borough | The neighbourhood or district within the city: Grünerløkka | The city has no such layer |
Street 1 / Street 2 | The street line. Two columns for header parity; in practice they hold the same value in almost every row. | No street address published |
City | City or town | Rural addresses |
Postal code | Postal code, local format | Not published on the listing |
State | Only for countries that have states. Empty for most of Europe — Norway, for instance, is empty in every row. | The country has no states |
Level 1 division | The first administrative layer under the country: région, county, Bundesland, state | The country has no level 1 |
Level 2 division | The second layer: département, Kreis, municipality | The country has no level 2 |
Country | Country name in English | Never |
Country code | ISO-3166 alpha-2: NO | Never |
Longitude / Latitude | Bare decimals, seven places, unpadded: 10.7821318. Longitude comes first. | Never |
Timezone | IANA name: Europe/Oslo | Never |
The two coordinate columns are their own group (location_coordinates), so you
can take the position without the eleven address columns — which is usually what a mapping job
wants. Note the order inside that group: longitude, then latitude. Most
mapping libraries want latitude first, so this is the single most common off-by-one-column bug
when someone reads the file by index.
Do not reconstruct an address by concatenation
Use Full address. Joining Street 1 to Postal code,
City and Country gives you a postal address in most countries and
a wrong one in several, because field order differs. And remember that
Full address leads with the business name — strip it if you are feeding a
geocoder.
Contact
| Column | Contains | Empty when |
|---|---|---|
Phone | National display format, spaced: +47 46 78 23 69 | No number published |
Phone international | The same number in E.164, no spaces: +4746782369. Use this one in code. | No number published |
Phone type | Mobile, Fixed line or Other. This is what the phone-type filter tests. | No number, or the type could not be classified |
Email | The best address found — the head of the ranked list that All emails holds in full | None found — common, and explained here |
Website | Full URL including the scheme | No website |
Website (root url) | The site root. In practice identical to Website in almost every row. | No website |
Every address in the file was published by the business on its own website; we do not guess addresses from a pattern. The eight further email columns — the role split, the named individual, and the full JSON array — are described in the enrichment columns.
Reviews and status
| Column | Contains | Empty when |
|---|---|---|
Reviews rating | Average star rating, one decimal: 4.4 | No reviews yet |
Reviews count | A band, not a number: 0, 1-50, 51-200, 201-500 or 501+ | No reviews data |
Is closed permanently | Yes or No. Always populated. | Never |
Working hours | A JSON object keyed monday…sunday | Hours not published |
Reviews count is a string, and it will break SUM()
It is the band the listing falls into, written as text — 1-50, not
37. This is the header contract, not a rounding choice, and it is the same
vocabulary the reviews-count filter uses, so a filter and a column always agree. If you need
a numeric threshold, filter on it rather than parsing it.
Working hours is a JSON object with seven keys, always in
monday…sunday order. A day is null when the hours are
unknown, the string "closed", the string "open-24-hours", a slug like
"9-am-5-pm" or "745-am-6-pm" where the colon is dropped, or an array
of slugs for a split shift.
Social profiles — six columns, then six more
Six single columns hold the first profile URL found for each network, in this header order:
Facebook link, Youtube link, Instagram link,
Linkedin link, Twitter link, Tiktok link. Six matching
All … columns hold every profile found for that network as a JSON array.
URLs are canonicalised before they are written: always https://, never
www., no tracking parameters, and Twitter stays on twitter.com rather
than x.com so that a value written last year still matches one written today.
The two social blocks are not in the same order
The single columns run Facebook, Youtube, Instagram, Linkedin, Twitter,
Tiktok. The All … columns run facebook, youtube, twitter, instagram,
linkedin, tiktok. Instagram, Twitter and Linkedin are transposed between the two
blocks. That is how the header contract is defined and we reproduce it deliberately, so that
a file diffed against the tool you are migrating from matches. Read these columns by
header name, never by offset.
The file itself is not what the extension says
This section matters more than it sounds like it should, because the file will open in a spreadsheet perfectly and then break a script that assumed the obvious.
| Property | Value |
|---|---|
| Extension | .csv |
| Delimiter | Tab — it is not comma-separated, despite the extension. 63 tabs in the header row. |
| Byte-order mark | Present. Three bytes of UTF-8 BOM at the very start, so Excel reads the encoding correctly. |
| Line ending | LF, not CRLF |
| Quoting | A field is quoted only when it contains a space, tab, quote or newline |
| Encoding | UTF-8 throughout |
| Empty JSON columns | An empty array is written as nothing at all, not [] |
So Name arrives unquoted and "Main type" arrives quoted, in the
same file. That is not an inconsistency to work around — it is the rule, applied per field.
Any real CSV parser handles it once you tell it the delimiter is a tab; a
split(",") will produce one enormous column and no error at all, which is the
failure mode worth knowing about.
Every format your plan includes is written at once
CSV and XLSX are generated together at export time on every plan, JSON as well from Growth, Parquet from Scale. You are not choosing between them when you create the export — you are choosing at download time, and you can take all of them, at no extra cost, from the same job. If a colleague wants the Excel version of something you already pulled as CSV, they do not need a new export. Choosing a format.
The canonical order, as one list
- Name
- Main type
- All types
- Google ID
- Link
- Phone
- Phone international
- Phone type
- Website
- Website (root url)
- Full address
- Borough
- Street 1
- Street 2
- City
- Postal code
- State
- Level 1 division
- Level 2 division
- Country
- Country code
- Longitude
- Latitude
- Timezone
- Reviews rating
- Reviews count
- Is closed permanently
- Working hours
- Facebook link
- Youtube link
- Instagram link
- Linkedin link
- Twitter link
- Tiktok link
- Website title
- Website meta description
- Website meta image
- Website meta generator
- Website lang
- Contact page 1
- Contact page 2
- Contact page 3
- Contact page 4
- Contact page 5
- All contact pages
- Individual email
- Individual email first name
- Individual email last name
- Contact email
- Sales email
- Marketing email
- Finance email
- Administration email
- All emails
- All facebook links
- All youtube links
- All twitter links
- All instagram links
- All linkedin links
- All tiktok links
- Website technologies
- Website ad pixels
- First seen on
Sixty-four, and the header row is exactly these names in exactly this order.
A real file with these columns is on the sample export, and you can download it before you have an account.
Updated on: