Is Price Tracker 2.0 - Price Graph & Auto Buy safe?

Medium risk

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.

IndiaDesire.comv3.7Chrome Web Store
45Risk
Who publishes it

Prijatel Internet Private Limited - no other listings under this identity, 3 shared hostnames

What this publisher told the store about itself, and the other listings that told it the same thing.

Publisher
IndiaDesire.com
Declared legal entity
Prijatel Internet Private Limited
Registered address
C-23, C Block, Sector 63, Noida, Uttar Pradesh 201301, IN
Registered contact
IndiaDesire.com

Shared hosts - 3 hostnames

Hostnames hardcoded in this extension that few other listings call. That can mean one operator behind both, and it can equally mean a small shared vendor, so it is context rather than a conclusion. Hosts that many listings call are left out: they are services, not connections.

assets.indiadesire.com
Also called by 1 other listing: FlashSale
dl.flipkart.com
Also called by 2 other listings: FlashSale, FlashSaleTricks
shop.vivo.com
Also called by 3 other listings, including FlashCart, FlashCart

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

MediumunwantedCWE-829Dynamic sandbox

Price Tracker 2.0 fetches selector rules from api2.indiadesire.com, cached under ptRemoteSelectors for flipkart.com.

What actually happens

You did this

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 did this

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.

Captured request

GEThttps://api2.indiadesire.com/n/m/api.php?rquest=getSelectors

The response is parsed as JSON selector data; dynamic analysis observed the parsed flipkart.com selector data being written to chrome.storage.local.

What's stored on your device

This cached record lets the extension reuse server-provided page-reading rules while you browse supported shopping sites.

Location
chrome.storage.local key 'ptRemoteSelectors'
Contents
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.

Selector-driven fields read from shopping pages

  • 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.

When this fires

Every 30 minutes

The selector rules are fetched once when the extension loads and then refreshed about every 30 minutes.

The code that does this

Remote selector fetch, cache, delivery, and use

Readable version

Service worker fetches and caches remote selectors

background.js
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();

Flipkart content script requests and applies those selectors

scripts/FlipV211.js
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;}

Background upload function posts collected records

background.js
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");}

Remote hosts used by this behavior

    • 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.

Where it sends data

Destinations our analysis observed Price Tracker 2.0 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.indiadesire.com

    Price Tracker 2.0 sends data to api.indiadesire.com. No other extension we have analyzed sends data here.

  • api2.indiadesire.com

    Price Tracker 2.0 sends data to api2.indiadesire.com. No other extension we have analyzed sends data here.

Updated 30 September 2026khmkmdkfllphcbkbkgflononijbkdgff