👀 Overview
Linkup can be used with GoogleSheet as a Formula to get contextual information from the internet.
📦 Installation
Setting Up Your Environment
-
Open your Google Sheet.
-
Go to Extensions > Apps Script.
- In the Apps Script editor, replace the existing code with the following script (you can use the “Copy” button on the top right of the code window 😊 ).
/**
* Linkup API configuration
*/
const API_ENDPOINT = 'https://api.linkup.so/v1/search';
/**
* Creates the menu item on install
*/
function onInstall(e) {
onOpen(e);
}
/**
* Creates the Add-On menu Linkup - Settings
*/
function onOpen(e) {
const ui = SpreadsheetApp.getUi();
ui.createAddonMenu()
.addItem('Settings', 'settings')
.addToUi();
}
/**
* Shows the settings dialog to configure the API key
*/
function settings() {
const ui = SpreadsheetApp.getUi();
const response = ui.prompt(
'Settings',
'Please enter your Linkup API Key (visit https://app.linkup.so/sign-up to get your free API key)',
ui.ButtonSet.OK_CANCEL
);
if (response.getSelectedButton() === ui.Button.OK) {
const apiKey = response.getResponseText();
if (apiKey) {
// Store in both UserProperties and ScriptProperties
PropertiesService.getUserProperties().setProperty('LINKUP_API_KEY', apiKey);
// This gives custom functions access to the key
PropertiesService.getScriptProperties().setProperty('USER_LINKUP_API_KEY', apiKey);
ui.alert('API key saved successfully');
} else {
ui.alert('Please enter a valid Linkup API key');
}
}
}
/**
* Returns the Linkup API key - tries UserProperties first, then falls back to ScriptProperties
*/
function getApiKey() {
// Try to get from user properties first
const userKey = PropertiesService.getUserProperties().getProperty('LINKUP_API_KEY');
if (userKey) return userKey;
// Fall back to script properties if user properties not accessible
return PropertiesService.getScriptProperties().getProperty('USER_LINKUP_API_KEY');
}
/**
* Returns the active cell
*/
function getActiveCell() {
return SpreadsheetApp.getActiveRange().getA1Notation();
}
/**
* Returns cells cache
*/
function getCache() {
return PropertiesService.getScriptProperties().getProperty('LINKUP_DATA')
? JSON.parse(PropertiesService.getScriptProperties().getProperty('LINKUP_DATA')) : {}
}
/**
* Overrides cells cache
*/
function saveCache(cache) {
PropertiesService.getScriptProperties()
.setProperty('LINKUP_DATA', JSON.stringify(cache));
}
/**
* Clears the cache of the active cell
*/
function deleteCellCache() {
const cache = getCache();
const activeCell = getActiveCell();
if (cache[activeCell]) {
delete cache[activeCell];
saveCache(cache);
}
}
/**
* Triggered on cell edit
*/
function onEdit(e) {
if (e.oldValue) {
deleteCellCache();
}
}
function askLinkup(query, include_sources) {
if (!query) return 'Please provide a search query';
const activeCell = getActiveCell();
const apiKey = getApiKey();
const cache = getCache();
console.log("api KEY=", apiKey ? "Found (not showing for security)" : "null");
console.log("cache =", cache);
if (!apiKey) {
return "No API key found. Please set up your API key in the Linkup menu -> Settings.";
}
// Check if this search has been cached
const existingEntry = cache[activeCell];
if (existingEntry
&& existingEntry.query === query
&& existingEntry.include_sources === include_sources) {
return existingEntry.response;
}
const options = {
method: 'post',
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
payload: JSON.stringify({
q: query,
depth: 'standard',
outputType: 'sourcedAnswer',
}),
muteHttpExceptions: true,
};
try {
const response = JSON.parse(
UrlFetchApp.fetch(API_ENDPOINT, options).getContentText()
);
if (response.answer) {
// Store include_sources in the cache
cache[activeCell] = {
query,
include_sources,
response
};
saveCache(cache);
}
return response;
} catch (error) {
return `Failed to process request: ${error.message}`;
}
}
/**
* Searches the Linkup API with the given query and returns the answer.
* @param {string} query The search query.
* @customfunction
*/
function LINKUP(query, includeSources=false) {
try {
const response = askLinkup(query, includeSources);
// Handle string responses (error messages)
if (typeof response === 'string') {
return response;
}
const answer = response.answer || 'No answer found';
if (!includeSources) {
return answer;
}
if (response.sources && response.sources.length > 0) {
return `${answer}\nSources: ${response.sources.map(({ url }) => url).join(':')}`
} else {
return `${answer}\nNo sources available`;
}
} catch (error) {
return `Error: ${error.message}`;
}
}
- Save and Run the script, review and accept permissions. This lets Sheets send Linkup your questions.
Save the script
Run the script
Review the permissions
Allow the permissions
You can rename the script to Linkup
Sometimes, you might see this screen that tells you our app hasn’t been authorized yet. Just click “Advanced” and “Authorize”
- Get an API Key:
Get your API key
Create a Linkup account for free to get your API key.
- In your Google Sheet, Extensions > Linkup For Google Sheets > Settings (the system may ask you confirmation to run a script)
- Enter your API Key and click
Ok
Congrats! You are now all setup to use Linkup on Sheets.
🤖 Usage
Use Linkup to answer your questions
- In a cell type:
You can also use a reference to a different cell:
- Press enter ✅
List sources in addition to the answer
- In a cell type:
=LINKUP("your query", TRUE)
You can also use a reference to a different cell:
- Press enter ✅