Assess a G2A Product Listing and Seller Risk Signals

Site g2a.comTask assess-g2a-product-listingVersion v2Updated Jul 29, 2026Category shopping

Resolve a G2A product from a name, inspect its listing and seller offers, and summarize price and visible trust or risk signals without guaranteeing safety. This skill was captured from a live agent session on g2a.com and is published here as a reusable recipe for agents.

NoteSelectors and URL schemes drift as sites change. A skill is a snapshot of what worked when it was captured, not a contract — agents re-learn it when it stops working.

Evaluate a G2A product listing for a requested title, price, seller information, and visible risk signals. Report evidence-based observations only; do not describe G2A or a seller as definitively safe or scam-free.

Use Cases

Use when the caller provides a product name, optionally a target price, and wants to know whether buying the corresponding G2A listing appears reasonable. The caller may provide a product URL or product identifier; otherwise resolve the opaque product ID from G2A search results.

Automation Flow

  1. If no product URL or opaque ID is provided, URL-encode the query and navigate directly to https://www.g2a.com/search?query={url-encoded-query}. In the same page evaluation, select product anchors whose href matches /-i\d+/ (usually a slug followed by i and the numeric product ID), and choose the result whose normalized visible text best matches {query} and the requested platform/region. Return its absolute URL and extracted ID. Do not guess an ID.
  2. Navigate directly to the resolved product URL, normally https://www.g2a.com/{slug}-i{product-id}. Allow the dynamically rendered offer area to load. If div[data-testid='ppa-offers-list__show-more-btn'] > button[type='button'] exists, activate it once to reveal additional offers, then extract the loaded page. The main offer container is commonly [data-testid='ppa-offers-list'] (with #offers or an [id*='offer'] fallback).
  3. Run this self-contained evaluator on the product page after offers are visible:
(() => {
 const clean = v => (v || '').replace(/\s+/g, ' ').trim();
 const text = el => clean(el?.innerText || el?.textContent || '');
 const amount = String.raw`(?:\d{1,3}(?:[.,\s]\d{3})+(?:[.,]\d{1,2})?|\d+(?:[.,]\d{1,2})?)`;
 const pricePattern = new RegExp(`(?:(?:[$€£]|USD|EUR|GBP)\\s*${amount}|${amount}\\s*(?:€|\\$|£))`, 'i');
 const money = s => (s.match(pricePattern) || [])[0] || null;
 const links = [...document.querySelectorAll('a[href]')].map(a => ({
   text: text(a), href: new URL(a.getAttribute('href'), location.href).href
 })).filter(x => x.text && x.href.includes(location.host));
 const offerNodes = [...document.querySelectorAll('[data-testid="ppa-offers-list"] [data-testid*="offer"], [data-testid="ppa-offers-list"] [data-testid*="seller"], [data-testid*="offer"], [data-testid*="seller"], [class*="offer"], [class*="seller"]')];
 const offers = [];
 const seen = new Set();
 for (const el of offerNodes) {
   const t = text(el);
   if (!t || t.length < 8 || t.length > 1200) continue;
   const key = t.slice(0, 500);
   if (seen.has(key)) continue;
   seen.add(key);
   const sellerLink = [...el.querySelectorAll('a[href]')].find(a => /seller|user|store|profile/i.test(a.getAttribute('href') || ''));
   const rating = (t.match(/\b(?:[1-5](?:[.,]\d)?\s*(?:out of 5|\/5)|[0-9]{1,3}(?:[.,][0-9]+)?%)/i) || [])[0] || null;
   offers.push({text: t, price: money(t), rating, seller: sellerLink ? text(sellerLink) : null});
   if (offers.length >= 30) break;
 }
 const body = text(document.body);
 return {
   url: location.href,
   title: clean(document.querySelector('h1')?.textContent || document.title),
   listedPrices: [...new Set((body.match(new RegExp(pricePattern.source, 'gi')) || []))].slice(0, 20),
   offers,
   visibleSignals: {
     keyType: (body.match(/Steam|Xbox|PlayStation|Nintendo|key|account|offline|activation/i) || [])[0] || null,
     regionTerms: [...new Set((body.match(/global|worldwide|EU|Europe|US|USA|region lock|region restricted/gi) || []))],
     refundTerms: [...new Set((body.match(/refund|return|money back|guarantee/gi) || []))],
     warnings: [...new Set((body.match(/warning|non-refundable|VPN|scam|risk|restricted|account/i) || []))]
   },
   relevantLinks: links.filter(x => /seller|support|refund|terms|review|rating/i.test(x.text + ' ' + x.href)).slice(0, 40)
 };
})()
  1. Compare the displayed total price, product/platform/region, seller rating and review count if exposed, offer age or sales history if exposed, payment/refund terms, and any account-versus-key or region-lock warning. A low price alone is not evidence of fraud. Recommend checking the exact seller, region, delivery type, refund policy, and payment protection before purchase.

Possible Friction Points

  • G2A search is directly addressable with https://www.g2a.com/search?query={url-encoded-query}; product pages use a slug plus an opaque numeric identifier such as ...-i10000503129005.
  • Never construct the numeric product ID from the title. Resolve it from a matching search result first, especially where multiple editions or platforms exist.
  • The offer list may initially be collapsed. The observed reveal control is div[data-testid='ppa-offers-list__show-more-btn'] > button[type='button']; use it only when present, then extract again.
  • Offers may render asynchronously after navigation; allow the offer area to populate before evaluating. The observed container selector is [data-testid='ppa-offers-list'], with #offers or an [id*='offer'] fallback.
  • Product and seller markup can change and class-based selectors may be less stable than data-testid attributes. Treat an empty offers array as incomplete evidence rather than proof that no sellers exist.
  • G2A is a marketplace, so platform trust does not establish that every seller or listing is safe. Distinguish marketplace-level information from seller-specific evidence and avoid guarantees.

Call it

GET https://production-sfo.browserless.io/skills?token=TOKEN-HERE&domain=g2a.com&task=assess-g2a-product-listing