/** * Keencrest: new news mentions of your brand, appended to a Google Sheet every hour. * Uses the GDELT News Monitor by Data Gleaner on Apify (watch mode: only articles not returned before). * https://apify.com/datagleaner/gdelt-news-monitor * Data: the GDELT Project, https://www.gdeltproject.org/ (citation required, included in each row). * * SETUP * 1. Extensions > Apps Script > paste this file > Project Settings > Script properties: * add APIFY_TOKEN = your own Apify API token (Apify Console > Settings > Integrations). * 2. Edit KEYWORDS below. Reload the sheet; a "Keencrest" menu appears. * 3. Run "Start hourly alert" once (authorise when asked). A "Mentions" tab is created and filled each hour. * "Check now" runs one pass immediately; "Stop alert" removes the trigger. * * COST: $0.002 per article returned, nothing when there is no new article. * MAX_USD is a hard cap per run (maxTotalChargeUsd). */ const KEYWORDS = ["YOUR BRAND", "YOUR PRODUCT"]; const EXCLUDE = []; // look-alike words to skip const LANGUAGES = ["en"]; // [] = every language (slower) const HOURS_BACK = 6; // look-back for the very first run only const MAX_ITEMS = 100; // per run const MAX_USD = 1; // maxTotalChargeUsd per run const WATCH_NAME = "brand-alert-sheet"; const TAB = "Mentions"; const ACTOR = "datagleaner~gdelt-news-monitor"; const HEADER = ["seen_at", "published_at", "title", "url", "source_domain", "language", "tone", "matched", "source"]; function onOpen() { SpreadsheetApp.getUi().createMenu("Keencrest") .addItem("Start hourly alert", "startHourly") .addItem("Check now", "checkMentions") .addItem("Stop alert", "stopHourly") .addToUi(); } function startHourly() { stopHourly(); ScriptApp.newTrigger("checkMentions").timeBased().everyHours(1).create(); checkMentions(); } function stopHourly() { ScriptApp.getProjectTriggers().forEach(t => { if (t.getHandlerFunction() === "checkMentions") ScriptApp.deleteTrigger(t); }); } function checkMentions() { const token = PropertiesService.getScriptProperties().getProperty("APIFY_TOKEN"); if (!token) throw new Error("Add the script property APIFY_TOKEN first (see the setup notes at the top)."); const url = "https://api.apify.com/v2/acts/" + ACTOR + "/run-sync-get-dataset-items?maxTotalChargeUsd=" + MAX_USD; const res = UrlFetchApp.fetch(url, { method: "post", contentType: "application/json", headers: { Authorization: "Bearer " + token }, payload: JSON.stringify({ keywords: KEYWORDS, excludeKeywords: EXCLUDE, languages: LANGUAGES, hoursBack: HOURS_BACK, watchMode: true, watchName: WATCH_NAME, maxItems: MAX_ITEMS }), muteHttpExceptions: true }); if (res.getResponseCode() !== 201) throw new Error(res.getResponseCode() + " " + res.getContentText().slice(0, 300)); const items = JSON.parse(res.getContentText()); if (!items.length) return 0; const ss = SpreadsheetApp.getActiveSpreadsheet(); const sheet = ss.getSheetByName(TAB) || ss.insertSheet(TAB); if (sheet.getLastRow() === 0) sheet.appendRow(HEADER); const rows = items.map(a => [a.seenAt || "", a.publishedAt || "", a.title || "", a.url || "", a.sourceDomain || "", a.language || "", typeof a.tone === "number" ? a.tone : "", (a.matchedKeywords || []).join(", "), "GDELT Project (gdeltproject.org)"]); sheet.getRange(sheet.getLastRow() + 1, 1, rows.length, HEADER.length).setValues(rows); return rows.length; }