Is Price Tracker 2.0 - Price Graph & Auto Buy safe?
Price Tracker 2.0 collects product data from 15+ e-commerce sites and transmits it, along with user agent and timezone, to api.indiadesire.com.
On each product page visit across sites including Amazon, Flipkart, Myntra, and a dozen others, the extension reads product ID, title, price, images, availability, seller details, and category, then POSTs that data to api.indiadesire.com together with the extension ID, user agent string, platform, and timezone. The DOM selectors that drive this extraction are fetched from api2.indiadesire.com every 30 minutes, meaning the operator can change what data is collected without an extension update.
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
Remote selectors control shopping-page collection
Price Tracker 2.0 fetches selector rules from api2.indiadesire.com, cached under ptRemoteSelectors for flipkart.com.
Content scripts read keys like title_sel, cprice_sel, img_sel, CatNames, cat_title_sel, cat_cprice_sel to pick page fields.
You browse a supported shopping page.
The extension runs content scripts on retail sites listed in its manifest, including Flipkart, Amazon, Myntra, Ajio, Snapdeal, Nykaa, Croma, and Tata Cliq.
The extension applies server-provided CSS selectors that decide which product details and page URL are collected.
The selector rules can change through the remote API response without shipping a new extension version.
This cached record lets the extension reuse server-provided page-reading rules while you browse supported shopping sites.
chrome.storage.local key 'ptRemoteSelectors'Dynamic analysis captured chrome.storage.local.set from the service worker writing ptRemoteSelectors with selector data for flipkart.com. The source writes an object shaped as { data: selectorsByDomain, timestamp: Date.now() }, where selectorsByDomain is built from the JSON returned by the getSelectors API.| Field | Value | Why it matters | |
|---|---|---|---|
Shopping page URL | https://www.flipkart.com/apple-iphone-15-blue-128-gb/p/itm6ac6485515ae4 (illustrative) | This ties the collected product record to the exact retail page you visited. | |
Product identifier | MOBGTAGPAQNVFZZY (illustrative) | This identifies the item on the retailer's site and makes repeat price checks possible. | |
Product title | Apple iPhone 15 (Blue, 128 GB) (illustrative) | This records the visible product name from the page you viewed. | |
Current price | 54999 (illustrative) | This records the current displayed price for the product page or listing card. | |
Product image URL | https://rukminim2.flixcart.com/image/416/416/xif0q/mobile/g/x/h/-original-imagtc5fz9spysyk.jpeg (illustrative) | This records the product image URL selected from the retailer page. | |
Availability and seller | marketplace=FLIPKART&lid=LSTMOBGTAGPAQNVFZZYFZVY2V; in stock (illustrative) | This adds shopping context such as stock status, marketplace, listing ID, and seller details. | |
Category path | Mobiles > Smartphones > Apple (illustrative) | This records category text from the page, which can describe what kind of products you viewed. |
The selector rules are fetched once when the extension loads and then refreshed about every 30 minutes.
Remote selector fetch, cache, delivery, and use
const STORAGE_KEY = 'ptRemoteSelectors';
const API_URL = 'https://api2.indiadesire.com/n/m/api.php?rquest=getSelectors';
const PTSELECTORS_DOMAINS = [
'amazon', 'flipkart', 'myntra', 'ajio', 'jiomart', 'purplle', 'snapdeal',
'shopclues', 'tatacliq', 'pepperfry', 'reliancedigital', 'nykaa', 'clovia',
'zivame', 'croma', 'meesho', 'amazoncn', 'amazonfr', 'amazonus', 'amazonuk', 'amazones'
];
async function fetchRemoteSelectors() {
try {
console.log('[PTExtn2] Fetching selectors from API...');
const response = await fetch(API_URL);
if (!response.ok) throw new Error('API fetch failed');
const json = await response.json();
// Convert array format to domain-keyed object
const selectorsByDomain = {};
for (const entry of json) {
for (const [domain, data] of Object.entries(entry)) {
if (Array.isArray(data) && data.length > 0) {
selectorsByDomain[domain] = data[0];
}
}
}
// Cache in chrome.storage
await chrome.storage.local.set({
[STORAGE_KEY]: {
data: selectorsByDomain,
timestamp: Date.now()
}
});
console.log('[PTExtn2] Cached selectors for:', Object.keys(selectorsByDomain).join(', '));
} catch (err) {
console.error('[PTExtn2] Fetch error:', err);
}
}
function initRemoteSelectors() {
fetchRemoteSelectors(); // Initial fetch
setInterval(fetchRemoteSelectors, 30 * 60 * 1000); // Every 30 mins
}
async function handleGetSelectors(domain, sendResponse) {
try {
// Try cache first
var cached = await chrome.storage.local.get(STORAGE_KEY);
if (cached[STORAGE_KEY]) {
var data = cached[STORAGE_KEY];
// Check if cache is fresh (30 mins TTL)
if (Date.now() - data.timestamp < 30 * 60 * 1000) {
var selectors = data.data[domain];
if (selectors) {
console.log('[PTExtn2] Serving cached selectors for:', domain);
sendResponse({success: true, selectors: selectors});
return;
}
}
}
// Fetch fresh if not in cache or expired
await fetchRemoteSelectors();
var fresh = await chrome.storage.local.get(STORAGE_KEY);
var selectors = fresh[STORAGE_KEY] ? fresh[STORAGE_KEY].data[domain] : null;
if (selectors) {
sendResponse({success: true, selectors: selectors});
} else {
sendResponse({success: false, error: 'No selectors for domain: ' + domain});
}
} catch (err) {
console.error('[PTExtn2] Error:', err);
sendResponse({success: false, error: err.message});
}
}
initRemoteSelectors();async function loadRemoteSelectors() {
await chrome.runtime.sendMessage({ action: 'getSelectors', domain: DOMAIN }, function(resp) {
if (resp && resp.success) {
remoteSelectors = resp.selectors;
setTimeout(sendPairs(1), 3000);
console.log('[Flipkart] Loaded remote selectors:', remoteSelectors ? Object.keys(remoteSelectors) : 'none');
}
});
}
function getExtn3Data() {
var m="",c="",s="";
if (!remoteSelectors || !remoteSelectors.CatNames) return { maincat: m, cat: c, subcat: s };
var sel = remoteSelectors.CatNames.split(',')[0].trim(); // First selector only
var all = $(sel);
if (all.length > 0) m = all.eq(1).text().trim(); // eq(0) - 1st
if (all.length > 1) c = all.eq(2).text().trim(); // eq(1) - 2nd
if (all.length > 2) s = all.eq(3).text().trim(); // eq(2) - 3rd
return { maincat: m, cat: c, subcat: s };
}
function getText(selKey) {
if (!remoteSelectors || !remoteSelectors[selKey]) return '';
var parts = remoteSelectors[selKey].split(',').map(s => s.trim()).filter(s => s);
for (var p of parts) {
var el = $(p);
if (el && el.length > 0) {
var txt = el.text().trim();
if (txt) return txt;
}
}
return '';
}
function getAttr(selKey, attr) {
if (!remoteSelectors || !remoteSelectors[selKey]) return '';
var parts = remoteSelectors[selKey].split(',').map(s => s.trim()).filter(s => s);
for (var p of parts) {
var el = $(p);
if (el && el.length > 0) {
var val = el.attr(attr) || el.prop(attr);
if (val) return val;
}
}
return '';
}
function getImage(){
var image = "";
image = getAttr('img_sel','src')||getAttr('img_sel','data-src');
return image;
}
function getCatDataSel() { return (remoteSelectors && remoteSelectors.cat_data_sel) || ''; }
function getCatTitleSel() { return (remoteSelectors && remoteSelectors.cat_title_sel) || ''; }
function getStockSel() { return (remoteSelectors && remoteSelectors.stock_sel) || ''; }
function getCatPriceSel() { return (remoteSelectors && remoteSelectors.cat_cprice_sel) || ''; }
function getCatImgSel() { return (remoteSelectors && remoteSelectors.cat_img_sel) || ''; }
function getCatBrandSel() { return (remoteSelectors && remoteSelectors.cat_brand_sel) || ''; }
function getCatCards() { var s = getCatDataSel(); return s ? $(s) : $(); }
function getPrice()
{
var currentPrice = getText('cprice_sel');
currentPrice = currentPrice.replace(/[^\d.]/g, '').replace(/^\./, '');
return filter_price(currentPrice);
}
function getTitle()
{
var title = getText('title_sel');
return title;
}function sendPairs(data, store,ctimezone) {
chrome.storage.local.get(['ptextid','ptextauth'], (result) => {
var parameters = "extnid="+result.ptextid+"&extnauth="+result.ptextauth+"&data=" + encodeURIComponent(data) + "&store=" + store+"&ctimezone="+ctimezone+"&version="+chrome.runtime.getManifest().version+"&useragent="+navigator.userAgent+"&platform="+navigator.platform;
let fetchData = {
method: 'POST',
body: parameters,
headers: new Headers({
'Content-Type': 'application/x-www-form-urlencoded'
})
};
fetch("https://api.indiadesire.com/v10/api.php?rquest=uploadData", fetchData)
.then((response) => response.json())
.then((responseData) => {
var abc=JSON.stringify(responseData);
});
});
// console.log("Success1");
}- api2.indiadesire.com
Provides the remote selector rules fetched by the service worker.
- api.indiadesire.com
Receives product records through the uploadData endpoint after content scripts build the data array.