Turn a column of names, emails, companies, or LinkedIn URLs into enriched rows — profile data, work emails, and company info — without leaving your spreadsheet. Install the official add-on for one-click LinkedIn lookups, or paste one short Apps Script function to reach all 20.
Extensions → Apps Script and call =LINKFINDER() in a cell. Nothing to install, and the code is yours to change.Sign up for free — your key is in your dashboard under Settings → API Key. New accounts start with 25 credits.
In your sheet, go to Extensions → Apps Script. Delete the placeholder code and paste the function from the next section. Then add your key under Project Settings → Script Properties as LF_KEY — the script reads it from there, so it is never sitting in the code you might share.
Replace YOUR_API_KEY with your key (or store it in Script Properties), then save the project.
Back in the sheet, type =LINKFINDER(A2, "company_name_to_website") in a cell and drag it down.
Looking someone up by name? Pass the company, location and job title too — =LINKFINDER(A2, "lead_full_name_to_email", B2, C2, D2). "John Smith" on its own matches thousands of people; "John Smith Acme Berlin VP Sales" matches one, and costs exactly the same. For big lists, use the batch script below.
lfCall helper, so paste the first block either way./**
* Enrich a value with LinkFinder AI.
*
* @param {string} input The cell to look up (name, email, company, or LinkedIn URL)
* @param {string} type The request type, e.g. "company_name_to_website"
* @param {string} company Optional. Name lookups only.
* @param {string} location Optional. Name lookups only.
* @param {string} jobTitle Optional. Name lookups only.
* @customfunction
*/
function LINKFINDER(input, type, company, location, jobTitle) {
if (!input || !type) return "";
var cell = function (v) { return Array.isArray(v) ? cell(v[0]) : v; };
var text = function (v) { return String(cell(v) == null ? "" : cell(v)).trim(); };
var value = text(input);
// The two name lookups take name + company + location + job title joined.
// A bare "John Smith" matches thousands of people for the same price as one
// that resolves, so send everything you have.
if (type.indexOf("lead_full_name_") === 0) {
// CRMs export "Doe, John". The lookup wants "John Doe".
var flip = value.match(/^\s*([^,]{1,60}?)\s*,\s*([^,]{1,60}?)\s*$/);
if (flip) value = flip[2] + " " + flip[1];
value = [value, text(company), text(location), text(jobTitle)]
.filter(String).join(" ");
}
return lfCall(type, value);
}
/** Shared by the formula and the batch script below. */
function lfCall(type, input) {
var key = PropertiesService.getScriptProperties().getProperty("LF_KEY");
if (!key) throw new Error("No API key. Project Settings \u2192 Script Properties \u2192 add LF_KEY.");
var res = UrlFetchApp.fetch("https://api.linkfinderai.com", {
method: "post",
contentType: "application/json",
headers: { Authorization: "Bearer " + key },
payload: JSON.stringify({ type: type, input_data: input }),
muteHttpExceptions: true
});
var code = res.getResponseCode();
var data = JSON.parse(res.getContentText() || "{}");
// These are NOT "not found" — surfacing them as such is how people burn an
// afternoon wondering why every row came back empty.
if (code === 401) throw new Error("API key rejected.");
if (code === 402) throw new Error("Out of credits.");
if (code === 429) throw new Error("Rate limited \u2014 wait a moment.");
if (code >= 400) throw new Error(data.message || ("LinkFinder error " + code));
// Some lookups answer with a job instead of a result and are never ready
// immediately \u2014 linkedin_profile_to_linkedin_info always does.
if (data.job_id) data = lfPoll(data.poll_url || ("https://api.linkfinderai.com/status/" + data.job_id), key);
var result = data.result;
if (result === null || result === undefined || result === "") return "Not found";
// A provider failure can arrive dressed as a successful result.
if (result && result.error) throw new Error("Provider error: " + (result.error.message || "unknown"));
return typeof result === "object" ? JSON.stringify(result) : result;
}
function lfPoll(url, key) {
for (var i = 0; i < 30; i++) {
Utilities.sleep(3000);
var r = UrlFetchApp.fetch(url, { headers: { Authorization: "Bearer " + key }, muteHttpExceptions: true });
var d = JSON.parse(r.getContentText() || "{}");
if (d.status && d.status !== "processing") return d.data || d;
}
throw new Error("Still running after 90s \u2014 use the batch script for this lookup.");
}=LINKFINDER() formula is perfect for a few rows, but Google Sheets can recalculate custom functions repeatedly — which re-spends credits and can hit script time limits on big sheets. For hundreds or thousands of rows, run the batch script instead: it processes each row once, skips rows already filled, and paces itself against rate limits.
| Lookup | Columns it reads | Credits per row |
|---|---|---|
| People | ||
Find LinkedIn URL from Namelead_full_name_to_linkedin_url |
Full Name + Company (optional) + Location (optional) + Job Title (optional) | 1 |
Find LinkedIn URL from Emailemail_to_linkedin_url |
Email Address | 5 |
Find Email from Namelead_full_name_to_email |
Full Name + Company (optional) + Location (optional) + Job Title (optional) | 7 |
Find Email from LinkedIn Profilelinkedin_profile_to_email |
LinkedIn Profile URL | 10 |
Get LinkedIn Profile Detailslinkedin_profile_to_linkedin_info |
LinkedIn Profile URL | 10 |
Find Phone from LinkedIn Profilelinkedin_profile_to_phone |
LinkedIn Profile URL | 50 |
| Companies | ||
Find Company Emailcompany_name_to_email |
Company Name | 1 |
Find Company Employee Countcompany_name_to_employee_count |
Company Name | 1 |
Find Company LinkedIn URLcompany_name_to_linkedin_url |
Company Name | 1 |
Find Company Phonecompany_name_to_phone |
Company Name | 1 |
Find Company Websitecompany_name_to_website |
Company Name | 1 |
Get Employee Count from LinkedIn Companylinkedin_company_to_employee_count |
LinkedIn Company Page URL | 1 |
List Employees by Company Domaincompany_domain_to_employees |
Company Domain | 0.5 × employees |
List Employees by Company Namecompany_name_to_employees |
Company Name | 0.5 × employees |
List Employees from LinkedIn Companylinkedin_company_to_employees |
LinkedIn Company Page URL | 0.5 × employees |
Get LinkedIn Company Detailslinkedin_company_to_linkedin_info |
LinkedIn Company Page URL | 6 |
| Social | ||
Get LinkedIn Post Reactionslinkedin_post_to_reactions |
LinkedIn Post URL | 1 |
Look Up an Instagram Profileinstagram_lookup |
Instagram Handle or URL | 1 |
| Discovery | ||
B2B Data Lookup (Any Input)b2b_data_lookup |
Company or Person Identifier | 1 |
lead_full_name_to_email is 7 credits a row
whether it matches the person you meant or someone else with the same name. Send the company, location and job title
alongside the name — it costs exactly the same and it is the difference between one match and thousands.
=LINKFINDER() in the built-in Apps Script editor and use it as a formula. Both call the same API and cost the same credits.type field. Full list in the API documentation.=LINKFINDER(A2, "lead_full_name_to_email", B2, C2, D2), or point the add-on's panel at those columns. "John Smith" matches thousands of people; "John Smith Acme Berlin VP Sales" matches one. Names exported from a CRM as Doe, John are flipped to John Doe for you.ERROR: instead is a failure worth reading — a rejected key or an empty credit balance stops the whole run rather than writing the same message into every remaining row.Get a free API key with 25 credits, paste the function, and enrich a column in minutes.
See the full topic → LinkedIn Data, Scraping & APIs hub