Is APK Downloader safe?
Search and download free Android app APK or XAPK files from APKPure.
This extension provides access to APKPure’s online APK downloader for finding free apps and games by app name or package name. It redirects users to an app information page where they can download available APK or XAPK files, including free apps that may be region-restricted on Google Play.
Who publishes itELECYBER - no other listings under this identity
ELECYBER - no other listings under this identity
What this publisher told the store about itself, and the other listings that told it the same thing.
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
Content script scans every page's DOM and reports it internally on load
APK Downloader's content script runs on every site, scanning the DOM for schema.org data on load and reporting the domain plus product fields to the background worker.
Kept only for ~2 dozen whitelisted app-store domains, else discarded.
What actually happens
You open, switch to, or navigate within any webpage in the browser.
The extension's content script immediately scans the page's DOM for structured product data and reports the domain and any extracted fields to the background service worker.
This happens at document_start, before the page has finished loading, on every site, not only app-store listings.
What the content script extracts and sends to the background script on every page
- Page domainwww.example-shop.com
The hostname of every site you visit is included in the internal message, whether or not the site is an app store.
- Structured product/app fieldscom.whatsapp
Any name, price, developer, rating, or package-ID data the page exposes via schema.org markup is pulled, on any site carrying it.
- Page titleWhatsApp Messenger
The extracted title of the product/app the page describes.
The code that does this
Content script scrapes DOM on load and on every SPA navigation (extract-package-info.605807e3.js)
const config = { run_at: "document_start" };// Runs immediately when the content script loads on ANY page.async function reportPageInfo() { chrome.runtime.sendMessage(buildPkgInfoMessage());}function buildPkgInfoMessage() { return { type: messageType.pkgInfo, data: extractProductDataFromDOM() };}function extractProductDataFromDOM() { // Look for schema.org itemprop="offers" elements const offersEls = document.querySelectorAll('[itemprop="offers"]'); let extracted = {}; const itempropEls = document.querySelectorAll('[itemprop]'); const jsonLdEls = document.querySelectorAll('[type="application/ld+json"]'); const wantedFields = ['image', 'name', 'priceCurrency', 'price', 'ratingValue', 'ratingCount', 'publisher', 'worstRating', 'bestRating']; const productTypes = ['MobileApplication', 'SoftwareApplication', 'Product', /* schema.org variants */]; // Try JSON-LD structured data first (runs on EVERY page with a matching <script type="application/ld+json">) try { jsonLdEls.forEach(el => { const data = JSON.parse(el.innerText); // ...matches against productTypes and captures the object into `extracted` }); } catch (e) {} // Fall back to itemprop microdata attributes if no JSON-LD matched if (itempropEls.length && !Object.keys(extracted).length) { itempropEls.forEach(el => { wantedFields.forEach(field => { if (el.getAttribute('itemprop') === field) { extracted[field] = el.content || el.src || el.innerText; } }); }); } // Per-site adjustments for ~23 known app-store domains (Google Play, App Store, APKPure, etc.) // ... return { url: extracted.url, domain: window.location.hostname, // sent for EVERY page, whitelisted or not packageId: extracted.packageId, icon: extracted.image, title: extracted.name, priceCurrency: extracted.priceCurrency, price: extracted.price, developer: extracted.publisher, ratingValue: extracted.ratingValue, reviewCount: extracted.ratingCount, worstRating: extracted.worstRating, bestRating: extracted.bestRating };}// Fires once on script load, and again on every SPA navigation.reportPageInfo();chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => { if (msg.type === messageType.getPkg) sendResponse(buildPkgInfoMessage());});window.addEventListener('hashchange', reportPageInfo);window.addEventListener('pushState', reportPageInfo);window.addEventListener('popstate', reportPageInfo);The code that does this
Background worker keeps data only for a hardcoded domain whitelist (background.93e42914.js)
// Called for every pkgInfo message received from the content script, on every page.function handlePkgInfo(message, tabId) { const isWhitelistedDomain = schemaWhiteUrlList.some(host => message.data.domain === host); // Record whether this page's domain was on the app-store whitelist — for EVERY page. chrome.storage.local.set({ isWhiteUrl: isWhitelistedDomain }); if (!isWhitelistedDomain) { clearBadge(tabId); return; // extracted data is discarded here, not persisted } setBadge(tabId, message.data.title ? '1' : ''); chrome.storage.local.set({ data: message.data.title ? JSON.stringify(message.data) : null, tabId: tabId });}chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { if (message?.type === messageType.pkgInfo) { handlePkgInfo(message, sender?.tab?.id); }});What's stored on your device
Every load writes isWhiteUrl true/false. Whitelisted domains also save scraped fields; 76 of 89 tested loads discarded data.
- Location
- chrome.storage.local keys 'isWhiteUrl' and 'data'
{ "isWhiteUrl": false, "note_non_whitelisted": "Observed 76 times during dynamic analysis testing on ordinary, non-app-store pages — each one a page load that triggered the DOM scan and internal message, then had its extracted data discarded because the domain wasn't on the whitelist.", "data_when_whitelisted_example": { "price": "0", "title": "WhatsApp Messenger", "developer": "WhatsApp LLC", "packageId": "com.whatsapp", "ratingValue": "4.2" }}Tab URL Sent to pureapk.com on Every Popup Open, Search, and Download
Opening the popup, searching, or clicking download sends your tab URL and a persistent device ID to tapi.pureapk.com.
Two confirmed GET requests carried the tab URL and stored client_id, building a browsing record tied to your device.
What actually happens
You open the extension popup on any browser tab, or type a search, or click the Download button.
The extension reads the URL of your current tab and sends it to tapi.pureapk.com together with a persistent device ID unique to your installation.
The beacon fires for three distinct actions: popup open (event_code=open), search bar submission (event_code=search), and download button click (event_code=download).
Captured request
HTTP 403. Endpoint confirmed reachable; the client_id (QwWhmueBPOqEA16zFKKBe) matched the value in chrome.storage.local key 'apk-downloader-uid'. A planted marker value appeared verbatim in the query string.
What the extension sends on each popup open, search, or download
- Current tab URLhttps://www.example.com/a planted marker value
The full address of the page you have open when you interact with the extension.
- Device ID (client_id)QwWhmueBPOqEA16zFKKBe
A permanent random ID created on install, stored locally, and sent every request, letting the server track your tab URLs over time.
- App partner ID (atta_id)05200075581
A hardcoded value that identifies this extension to the pureapk.com backend. The same for all users.
- Action type (event_code)open
Which user action triggered the beacon: opening the popup, running a search, or clicking download.
- Noise salt (random)0.8631820457615105
A random float added to each request, likely to prevent caching, not for privacy.
What's stored on your device
Created via nanoid on install, never rotated. Sent as client_id on every request, tying every tab URL you report to the same device.
- Location
- chrome.storage.local key 'apk-downloader-uid'
{ "apk-downloader-uid": "QwWhmueBPOqEA16zFKKBe"}The code that does this
The reportAtta function that fires the beacon, shipped minified vs. readable.
reportAtta — creates or retrieves persistent UUID, then sends beacon
// Called by background onMessage handler whenever popup sends a 'report' message.async function reportAtta(eventCode, extraInfo = {}) { // Read the persistent device UUID from storage (creates one on first run). let { 'apk-downloader-uid': clientId } = await chrome.storage.local.get('apk-downloader-uid'); if (!clientId) { clientId = nanoid; // generates a URL-safe random 21-char ID await chrome.storage.local.set({ 'apk-downloader-uid': clientId }); } // Build the query string and fire the GET beacon. const params = new URLSearchParams({ atta_id: '05200075581', // hardcoded partner ID random: Math.random.toString, // cache-busting noise client_id: clientId, // persistent per-device UUID event_code: eventCode, // 'open' | 'search' | 'download' | 'install' ...extraInfo // includes { url: <current_tab_url> } }); await fetch(`https://tapi.pureapk.com/report/search_report?${params}`);}Popup mount effect — triggers open beacon with current tab URL
// Runs once when the popup loads.useEffect(async => { const [tab] = await chrome.tabs.query({ active: true, currentWindow: true }); if (!tab) return; // Send 'open' event to background with the current tab's URL. chrome.runtime.sendMessage({ type: 'report', data: { eventCode: 'open', extraInfo: { url: tab.url || '' } } }); // ... then fetch APK info for the page }, []);Where the data is sent
- tapi.pureapk.com
Analytics API for APK Pure (pureapk.com), the extension's parent site. Receives the tab URL, persistent device ID, and event type on every popup interaction.
Reproduce it yourself
Run this in the DevTools console on the extension's background service worker to intercept all outbound beacons to tapi.pureapk.com and log their full query parameters in readable form.
- Chrome with Developer mode enabled
- APK Downloader extension installed
// apk-downloader-beacon-watcher.js// Patches globalThis.fetch in the APK Downloader background service worker// to intercept and log every call to tapi.pureapk.com/report/search_report.//// Usage:// 1. Open chrome://extensions, enable Developer mode.// 2. Find "APK Downloader" and click its service worker link.// 3. In the DevTools console that opens, paste this entire script.// 4. Click the APK Downloader toolbar icon on any page.// 5. Watch for [APK_BEACON] entries in the console.(function { const TARGET = 'tapi.pureapk.com/report/search_report'; const origFetch = globalThis.fetch.bind(globalThis); globalThis.fetch = function (input, init) { const url = typeof input === 'string' ? input : input?.url ?? ''; if (url.includes(TARGET)) { try { const parsed = new URL(url); const params = {}; parsed.searchParams.forEach((v, k) => { params[k] = v; }); console.log('[APK_BEACON] Outbound beacon intercepted:'); console.log(' URL: ', url); console.log(' client_id: ', params.client_id, ' ← persistent device UUID'); console.log(' event_code: ', params.event_code, ' ← open | search | download | install'); console.log(' url: ', params.url, ' ← current tab URL at time of action'); console.log(' atta_id: ', params.atta_id); console.log(' random: ', params.random); console.log(' full params:', params); } catch (e) { console.error('[APK_BEACON] Parse error:', e); } } return origFetch(input, init); }; console.log('[APK_BEACON_WATCHER] Installed. Open the APK Downloader popup to capture beacons.');});- 1Open chrome://extensions, enable Developer mode.
- 2Open APK Downloader's service worker inspector.
- 3Paste this script, press Enter.
- 4Visit any page, click the toolbar icon.
- 5Look for [APK_BEACON] logs with tab URL and client_id.
Persistent device ID and active tab URL sent to pureapk.com on popup open
Each time you open the APK Downloader popup on an HTTP page, the extension sends a permanent device ID and your tab's URL to tapi.pureapk.com.
The ID is generated once and stored permanently, recording pages open each check.
What actually happens
You open the APK Downloader popup while on any HTTP page.
The extension immediately sends your permanent device ID and the current page URL to tapi.pureapk.com.
No download action required, opening the popup is sufficient to trigger the report.
Captured request
Confirmed via dynamic analysis (DA network row 267): GET fired immediately on popup open with persistent client_id and active tab URL.
Data sent to tapi.pureapk.com on every popup open
- Your permanent device IDjRuJDKtkbHgh8TWIIg0Qz
A random identifier created on first install and stored forever. Links every popup open back to your specific browser installation.
- The page you had openhttps://www.example.com/some-page
The full URL of the active tab when you opened the popup, reveals which sites you were visiting at that moment.
- Analytics account ID05200075581
A hardcoded code that identifies this extension's analytics account at pureapk.com.
- Random noise value0.7341829471
A per-request random number included alongside the stable identifiers.
The code that does this
Tracking function in background service worker (background.93e42914.js:205-219)
async function reportAtta(eventCode, extraInfo = {}) { // Retrieve or create the persistent device identifier let { [KEY_UID]: clientId } = await chrome.storage.local.get(KEY_UID); if (!clientId) { clientId = nanoid(); await chrome.storage.local.set({ [KEY_UID]: clientId }); } // Build query string with permanent ID + current event data const params = new URLSearchParams({ atta_id: "05200075581", // hardcoded analytics account random: Math.random().toString(), client_id: clientId, // persistent device ID event_code: eventCode, ...extraInfo // includes { url: activeTabUrl } }); await fetch(`https://tapi.pureapk.com/report/search_report?${params}`);}Where the data is sent
- tapi.pureapk.com
Analytics backend operated by pureapk.com, the extension's developer. Receives the persistent device ID, active tab URL, and event type on every popup open.
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 secure site you visit
https://*/*
See the address and title of every tab you have open
tabs
Store data in your browser
storage
Add items to the right-click menu
contextMenus
Act on the current tab, but only after you click the extension
activeTab
Where it sends data
Destinations our analysis observed APKPure 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.
- APKPure.com
APKPure sends data to APKPure.com. No other extension we have analyzed sends data here.