Overview
- grabs the Country/Territory list (from the hidden dropdown),
- fetches the full ICANN CSV via the page’s own download link (respects whatever filters you’ve set; clear filters to get all 3,020),
- parses it in-browser,
- saves 3 handy files:
icann-registrars-raw.csv(ICANN’s full export),icann-registrars-by-country.csv(summary counts),icann-registrars-gname.csv(subset where name starts with “Gname…”).
It’s robust to commas/quotes in company names and doesn’t click through pages.
// Paste into DevTools on the ICANN registrars page and hit Enter
(async () => {
const sleep = ms => new Promise(r => setTimeout(r, ms));
// ---------- helpers ----------
const dl = (filename, text, type = 'text/csv') => {
const blob = new Blob([text], { type });
const a = document.createElement('a');
a.href = URL.createObjectURL(blob);
a.download = filename;
document.body.appendChild(a);
a.click();
a.remove();
};
const csvEscape = v => `"${String(v ?? '').replace(/"/g, '""')}"`;
const toCSV = (rows, headerKeys, headerLabels) => {
const head = headerLabels.map(csvEscape).join(',');
const body = rows.map(r => headerKeys.map(k => csvEscape(r[k])).join(',')).join('\n');
return head + '\n' + body;
};
// RFC4180-ish CSV parser (handles quotes, embedded commas/newlines, and "" escapes)
const parseCSV = (text) => {
const rows = [];
let i = 0, field = '', row = [], inQuotes = false;
while (i < text.length) {
const c = text[i];
if (inQuotes) {
if (c === '"') {
if (text[i + 1] === '"') { field += '"'; i += 2; continue; } // escaped quote
inQuotes = false; i++; continue; // closing quote
}
field += c; i++; continue;
}
if (c === '"') { inQuotes = true; i++; continue; }
if (c === ',') { row.push(field); field = ''; i++; continue; }
if (c === '\r') { i++; continue; }
if (c === '\n') { row.push(field); rows.push(row); row = []; field = ''; i++; continue; }
field += c; i++;
}
// trailing field
if (field.length || row.length) { row.push(field); rows.push(row); }
const headers = rows.shift() || [];
const idx = Object.fromEntries(headers.map((h, j) => [h.trim(), j]));
const recs = rows.filter(r => r.length).map(r => new Proxy(r, {
get: (_, key) => r[idx[key]] ?? ''
}));
recs._headers = headers;
return recs;
};
// ---------- Countries from the dropdown (even if hidden) ----------
const countryInput = document.querySelector('#country-territory');
let countryOptions = [];
if (countryInput) {
const countryDropdown = countryInput.closest('iti-multiselect-dropdown')?.querySelector('.search-drop-down');
if (countryDropdown) {
countryOptions = [...countryDropdown.querySelectorAll('label.search-drop-down__item span')]
.map(s => (s.textContent || '').trim())
.filter(Boolean);
const countriesCSV = 'Country/Territory\n' + countryOptions.map(c => csvEscape(c)).join('\n');
dl('icann-countries.csv', countriesCSV);
}
}
// ---------- Fetch ICANN’s CSV (respects current filters) ----------
// If filters are applied, you get the filtered dataset. Clear filters to get all 3020.
let csvURL = document.querySelector('a[data-testid="csv-download"]')?.href
|| 'https://www.icann.org/en/contracted-parties/accredited-registrars/list-of-accredited-registrars/csvdownload';
// Wait a tick in case the link is still rendering
if (!csvURL.includes('/csvdownload')) {
await sleep(400);
csvURL = document.querySelector('a[data-testid="csv-download"]')?.href || csvURL;
}
const resp = await fetch(csvURL, { credentials: 'include' });
if (!resp.ok) throw new Error(`CSV download failed: ${resp.status}`);
const rawCSV = await resp.text();
dl('icann-registrars-raw.csv', rawCSV);
// ---------- Parse and make the extra files ----------
const records = parseCSV(rawCSV);
const headers = records._headers;
// Try to locate relevant columns by name (defensive on exact header text)
const col = (want) => headers.find(h => h.toLowerCase().includes(want)) || want;
const COL_NAME = col('registrar name');
const COL_IANA = col('iana');
const COL_COUNTRY = col('country');
const COL_WEBSITE = col('website');
const COL_PCNAME = col('public contact name');
const COL_PCPHONE = col('public contact phone');
const COL_PCEMAIL = col('public contact email');
// Summary by country
const byCountry = new Map();
for (const r of records) {
const c = (r[COL_COUNTRY] || '').trim() || 'Unknown';
byCountry.set(c, (byCountry.get(c) || 0) + 1);
}
const countryRows = [...byCountry.entries()]
.sort((a,b) => b[1]-a[1])
.map(([country, count]) => ({ country, count }));
const countryCSV = toCSV(countryRows, ['country','count'], ['Country/Territory','Count']);
dl('icann-registrars-by-country.csv', countryCSV);
// Gname-only subset
const gnameRows = records
.filter(r => String(r[COL_NAME]).match(/^\s*gname\b/i))
.map(r => ({
name: r[COL_NAME],
iana: r[COL_IANA],
country: r[COL_COUNTRY],
website: r[COL_WEBSITE],
contact_name: r[COL_PCNAME],
contact_phone: r[COL_PCPHONE],
contact_email: r[COL_PCEMAIL],
}));
const gnameCSV = toCSV(
gnameRows,
['name','iana','country','website','contact_name','contact_phone','contact_email'],
['Registrar','IANA','Country/Territory','Website','Public Contact Name','Public Contact Phone','Public Contact Email']
);
dl('icann-registrars-gname.csv', gnameCSV);
console.log('%cDone!', 'color:#06f;font-weight:bold;');
console.log(`Countries: ${countryOptions.length} • Registrars in CSV: ${records.length} • Gname subset: ${gnameRows.length}`);
})();
Want me to also spit out other “families” (e.g., DropCatch, Sav.com shards, SNAPNAMES ##, NamePal, Dynadot, etc.) as their own CSVs or include a brand-group summary?
Key terms in plain language
Open a term for a concise explanation of language used on this page.
VoIP
Voice over Internet Protocol carries phone calls over an IP network instead of a traditional analog phone line. Call quality depends on network stability, latency, and traffic management.
Unified Communications (UCaaS)
A cloud-based combination of business calling, messaging, meetings, presence, and collaboration tools managed as one communications service.
SIP Trunking
A service that connects a business phone system to the public telephone network using Internet Protocol, replacing or supplementing traditional phone lines.
Bandwidth
The amount of data a connection can carry in a given time, usually measured in Mbps or Gbps. More bandwidth supports more users, devices, and simultaneous applications.
Latency
The time it takes data to travel between two points. Lower latency improves voice, video meetings, cloud applications, gaming, and other real-time services.
Service-Level Agreement (SLA)
A provider’s written commitment covering service targets such as availability, response time, repair time, and sometimes financial credits when commitments are missed.