Claude Skills Guide

Chrome Extension Credit Card Rewards Optimizer: A Developer Guide

Credit card rewards optimization has evolved beyond manual spreadsheets. Developers and power users now leverage Chrome extensions to automatically calculate the best card for each purchase, track earning rates, and maximize points redemption values. This guide explores the technical architecture behind these tools and provides practical implementation patterns for building your own rewards optimizer.

Understanding the Core Architecture

A Chrome extension for credit card rewards optimization typically consists of three main components: a content script that detects transaction details on merchant websites, a background service worker for data processing and card matching, and a popup interface for displaying results to users.

The content script scrapes merchant identity information from the page DOM, including merchant category codes (MCC), product names, and transaction amounts. This data gets sent to the background script, which maintains a local database of card reward structures and applies matching logic to determine the optimal card.

Here’s a basic content script that extracts merchant information:

// content-script.js
function extractMerchantInfo() {
  const merchantElement = document.querySelector('[data-merchant-name], .merchant-header, #merchantName');
  const amountElement = document.querySelector('[data-amount], .total-amount, #orderTotal');

  return {
    merchant: merchantElement?.textContent?.trim() || document.domain,
    amount: parseFloat(amountElement?.textContent?.replace(/[^0-9.]/g, '') || '0'),
    url: window.location.href,
    category: detectCategory()
  };
}

function detectCategory() {
  const metaDescription = document.querySelector('meta[name="description"]')?.content || '';
  const pageTitle = document.title.toLowerCase();
  const bodyText = document.body?.innerText?.toLowerCase() || '';

  // Common merchant category patterns
  const categories = {
    'dining': ['restaurant', 'cafe', 'coffee', 'food', 'pizza', 'burger'],
    'groceries': ['grocery', 'supermarket', 'whole foods', 'trader joe'],
    'gas': ['gas', 'fuel', 'shell', 'chevron', 'exxon'],
    'travel': ['airline', 'hotel', 'airbnb', 'flight', 'booking'],
    'streaming': ['netflix', 'spotify', 'hulu', 'disney+', 'streaming']
  };

  const searchText = `${metaDescription} ${pageTitle} ${bodyText}`;

  for (const [category, keywords] of Object.entries(categories)) {
    if (keywords.some(kw => searchText.includes(kw))) {
      return category;
    }
  }

  return 'general';
}

// Send to background script
chrome.runtime.sendMessage({
  type: 'MERCHANT_DETECTED',
  payload: extractMerchantInfo()
});

Card Database and Matching Logic

The background script maintains a structured database of credit card reward rates. For a production implementation, you would store this data in Chrome’s storage API with versioning to handle rate changes:

// background.js - Card database structure
const cardDatabase = {
  'chase_sapphire_preferred': {
    name: 'Chase Sapphire Preferred',
    rates: {
      'dining': 3,
      'streaming': 3,
      'online_grocery': 3,
      'travel': 2,
      'general': 1
    },
    annualFee: 95,
    redemptionBonus: 0.25 // 25% boost when redeemed for travel
  },
  'amex_gold': {
    name: 'American Express Gold Card',
    rates: {
      'dining': 4,
      'groceries': 4,
      'gas': 1,
      'general': 1
    },
    annualFee: 250
  },
  'capital_one_venture_x': {
    name: 'Capital One Venture X',
    rates: {
      'travel': 10, // Via travel portal
      'hotels': 10,
      'general': 2
    },
    annualFee: 395
  }
};

// Matching function
function findBestCard(merchantInfo) {
  const { category, amount } = merchantInfo;
  let bestCard = null;
  let maxRate = 0;

  for (const [cardId, cardData] of Object.entries(cardDatabase)) {
    const rate = cardData.rates[category] || cardData.rates.general || 0;
    if (rate > maxRate) {
      maxRate = rate;
      bestCard = { id: cardId, ...cardData, appliedRate: rate };
    }
  }

  return bestCard;
}

Building the Popup Interface

The popup provides real-time feedback when users click the extension icon. Implementing a clean interface requires handling the message passing between popup and background script:

// popup.js
document.addEventListener('DOMContentLoaded', async () => {
  // Get current tab info
  const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });

  // Request merchant info from content script
  chrome.tabs.sendMessage(tab.id, { type: 'GET_MERCHANT_INFO' }, async (response) => {
    if (chrome.runtime.lastError || !response) {
      showNoDataMessage();
      return;
    }

    // Get best card recommendation
    const recommendation = await chrome.runtime.sendMessage({
      type: 'GET_RECOMMENDATION',
      payload: response
    });

    renderRecommendation(recommendation);
  });
});

function renderRecommendation(card) {
  const container = document.getElementById('results');
  container.innerHTML = `
    <div class="best-card">
      <h3>Recommended: ${card.name}</h3>
      <p class="rate">${card.appliedRate}x points on this purchase</p>
      <p class="earnings">You'll earn ~${Math.round(card.appliedRate * 100)} points</p>
    </div>
  `;
}

Handling Dynamic Content and Edge Cases

Modern e-commerce sites use dynamic content loading, which requires MutationObserver to detect when merchant information becomes available:

// Enhanced content-script.js
const observer = new MutationObserver((mutations) => {
  const merchantInfo = extractMerchantInfo();
  if (merchantInfo.merchant && merchantInfo.amount > 0) {
    chrome.runtime.sendMessage({
      type: 'MERCHANT_DETECTED',
      payload: merchantInfo
    });
  }
});

// Start observing when DOM is ready
observer.observe(document.body, {
  childList: true,
  subtree: true,
  characterData: true
});

For sites with authentication walls or single-page applications, you may need to inject scripts that hook into JavaScript data stores directly. This approach extracts information from React/Vue/Angular state:

function extractFromReactState() {
  // Attempt to read React fiber tree (simplified example)
  const root = document.querySelector('#root');
  if (root && root._reactRootContainer) {
    // Access internal React data - requires debugging knowledge
    return null; // Complex implementation varies by React version
  }

  // Alternative: Look for data attributes
  const checkoutData = document.querySelector('[data-cart-total], [data-order-amount]');
  if (checkoutData) {
    return {
      amount: parseFloat(checkoutData.dataset.cartTotal || checkoutData.dataset.orderAmount || 0)
    };
  }

  return null;
}

Data Privacy Considerations

When building rewards optimizer extensions, handle user financial data carefully. Store card information locally using Chrome’s encrypted storage rather than transmitting sensitive data:

// Secure storage for card data
async function saveCardData(cardId, cardData) {
  await chrome.storage.session.set({
    [cardId]: {
      ...cardData,
      lastUpdated: Date.now()
    }
  });
}

// Never store: full card numbers, CVV, PINs
// Only store: card name, reward rates, annual fee, issuer

Extension Manifest Configuration

Your extension needs proper permissions in the manifest file:

{
  "manifest_version": 3,
  "name": "Credit Card Rewards Optimizer",
  "version": "1.0",
  "permissions": [
    "storage",
    "activeTab",
    "scripting"
  ],
  "host_permissions": [
    "*://*.amazon.com/*",
    "*://*.walmart.com/*",
    "*://*.target.com/*",
    "*://*/*"
  ],
  "content_scripts": [{
    "matches": ["<all_urls>"],
    "js": ["content-script.js"]
  }],
  "background": {
    "service_worker": "background.js"
  },
  "action": {
    "default_popup": "popup.html"
  }
}

Key Limitations and Workarounds

Chrome extensions face inherent limitations for rewards optimization. They cannot access mobile apps, in-store transactions, or merchant sites that require API authentication. Additionally, reward rates change frequently—maintaining an accurate database requires regular updates from user reports or manual entry.

For comprehensive optimization, pair your extension with manual tracking for offline purchases and annual fee calculations. The extension handles the quick decision-making at checkout; you handle the strategic optimization.

Built by theluckystrike — More at zovo.one