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.comv2.43Chrome Web Store
45Risk

AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.

Publishers can request a review.

Findings

SeverityMEDIUM
ClassUNWANTED
TypeUnexpected
CWECWE-829
SourceAI SANDBOX

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.

01EvidenceCAUSE EFFECT
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.

02EvidenceNETWORK CAPTURE
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.
03EvidenceSTORAGE DUMP
What's stored on your device

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

Locationchrome.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.
04EvidenceFIELD TABLE
Selector-driven fields read from shopping pages
FieldValueWhy 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.
05EvidenceTEMPORAL PATTERN
When this fires
Every 30 minutes

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

06EvidenceCODE COMPARE
The code that does this

Remote selector fetch, cache, delivery, and use

What it actually does
Service worker fetches and caches remote selectorsbackground.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 selectorsscripts/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 recordsbackground.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");

}
07EvidenceTHIRD PARTY LIST
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.

Data recipients

api.indiadesire.comapi2.indiadesire.com
Updated 17 September 2026khmkmdkfllphcbkbkgflononijbkdgff