Lazada Market — Blogger Affiliate Store

Lazada Market — Blogger Affiliate Store

We'll build Lazada Market, a mixed-product affiliate storefront for Philippine shoppers, with live product data loaded from Google Sheets and purchase links tracked through Involve Asia.

The setup uses Blogger for the website, your existing 15-column CSV schema for products, and JavaScript for searching, filtering, and sorting. Google Sheets supports publishing an individual spreadsheet or sheet to the web, while Blogger supports HTML and CSS customization.

Google Docs Editors Help
+1

Lazada Market

Discover great finds for everyday life.

Product search
Category filter
Price sorting
Affiliate links

Step 1 — Prepare your product catalog

Start with the sample CSV you already have:

Download blogger_lazada_affiliate_sample.csv

Import it into Google Sheets and replace the demonstration entries with real product information. Keep these column names exactly as they are:

product_id, title, category, price, currency, original_price, discount_percent, rating, review_count, image_url, product_url, affiliate_url, description, availability, last_updated

For every product, the affiliate_url must contain your generated Involve Asia tracking link. Involve Asia explains that publisher tracking links are generated for approved offers and can direct shoppers to specific product pages when deeplinking is supported.

Involve Asia
+1

Step 2 — Publish the Google Sheet as CSV

  1. Open the spreadsheet in Google Sheets.

  2. Choose File → Share → Publish to web.

  3. Select the worksheet containing the product catalog.

  4. Select CSV as the output format, if offered.

  5. Click Publish, confirm, and copy the resulting URL.

  6. Open that URL in a new browser tab and verify that it returns comma-separated product data.

Google's official instructions describe publishing spreadsheets or individual sheets and copying the resulting public URL.

Google Docs Editors Help

Keep your unpublished working spreadsheet private if desired; publish only the product catalog that shoppers are allowed to see. The published sheet must not contain private notes, credentials, or other sensitive information.

Step 3 — Add the storefront to Blogger

In Blogger, create a new page called Shop. Switch to the HTML editor and paste the complete code below.

Before publishing, replace PASTE_YOUR_PUBLISHED_CSV_URL_HERE with your Google Sheets published CSV URL.


<div id="lm-store">
  <header class="lm-hero">
    <p class="lm-eyebrow">YOUR EVERYDAY FINDS</p>
    <h1>Lazada Market</h1>
    <p>Discover useful products, compare prices, and find your next great deal.</p>
    <a href="#lm-products" class="lm-hero-btn">Explore Products ↓</a>
  </header>

  <section class="lm-shop">
    <div class="lm-section-heading">
      <div>
        <h2>Shop Our Picks</h2>
        <p id="lm-count">Loading products...</p>
      </div>
    </div>

    <div class="lm-toolbar">
      <label class="lm-search-wrap">
        <span>Search products</span>
        <input id="lm-search" type="search"
          placeholder="Search gadgets, home items..." />
      </label>

      <label>
        <span>Category</span>
        <select id="lm-category">
          <option value="">All categories</option>
        </select>
      </label>

      <label>
        <span>Sort by</span>
        <select id="lm-sort">
          <option value="featured">Featured</option>
          <option value="price-asc">Price: Low to High</option>
          <option value="price-desc">Price: High to Low</option>
          <option value="name-asc">Name: A to Z</option>
        </select>
      </label>
    </div>

    <p id="lm-status" role="status" aria-live="polite">
      Loading the catalog...
    </p>
    <div id="lm-products" class="lm-grid"></div>
  </section>

  <footer class="lm-footer">
    <p><strong>Lazada Market</strong> · Your everyday shopping guide</p>
    <p class="lm-disclosure">
      Affiliate disclosure: This website contains affiliate links.
      We may earn a commission from qualifying purchases at no
      additional cost to you. Product prices and availability may change.
    </p>
  </footer>
</div>

<style>
  #lm-store {
    --lm-orange: #f57224;
    --lm-ink: #252525;
    --lm-muted: #6b7280;
    --lm-line: #e8e8e8;
    color: var(--lm-ink);
    font-family: Arial, Helvetica, sans-serif;
    line-height: 1.5;
    max-width: 1200px;
    margin: 0 auto;
  }

  #lm-store * {
    box-sizing: border-box;
  }

  #lm-store .lm-hero {
    padding: 48px 24px;
    border-radius: 16px;
    background: linear-gradient(120deg, #fff0e5, #fffaf5);
    text-align: center;
    margin-bottom: 34px;
  }

  #lm-store .lm-eyebrow {
    color: #a9470b;
    font-size: 12px;
    font-weight: 800;
    letter-spacing: 2px;
  }

  #lm-store .lm-hero h1 {
    font-size: clamp(32px, 5vw, 48px);
    line-height: 1.15;
    margin: 12px 0;
    color: #222;
  }

  #lm-store .lm-hero p {
    max-width: 600px;
    margin: 12px auto;
  }

  #lm-store .lm-hero-btn,
  #lm-store .lm-buy {
    display: inline-block;
    background: var(--lm-orange);
    color: #fff !important;
    border: 0;
    border-radius: 8px;
    padding: 12px 18px;
    text-decoration: none !important;
    font-weight: 700;
    text-align: center;
  }

  #lm-store .lm-hero-btn {
    margin-top: 12px;
  }

  #lm-store .lm-section-heading h2 {
    margin-bottom: 2px;
    font-size: 28px;
  }

  #lm-store .lm-section-heading p {
    color: var(--lm-muted);
    margin-top: 0;
  }

  #lm-store .lm-toolbar {
    display: grid;
    grid-template-columns: minmax(180px, 2fr) minmax(150px, 1fr)
      minmax(160px, 1fr);
    gap: 14px;
    margin: 22px 0;
  }

  #lm-store .lm-toolbar label {
    display: flex;
    flex-direction: column;
    gap: 6px;
    font-size: 13px;
    font-weight: 700;
  }

  #lm-store input,
  #lm-store select {
    width: 100%;
    min-width: 0;
    padding: 12px;
    background: #fff;
    color: #222;
    border: 1px solid #d7d7d7;
    border-radius: 8px;
    font: inherit;
  }

  #lm-store .lm-grid {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 18px;
  }

  #lm-store .lm-card {
    display: flex;
    flex-direction: column;
    min-width: 0;
    overflow: hidden;
    border: 1px solid var(--lm-line);
    border-radius: 12px;
    background: #fff;
    transition: box-shadow .2s ease, transform .2s ease;
  }

  #lm-store .lm-card:hover {
    box-shadow: 0 6px 24px #00000012;
    transform: translateY(-2px);
  }

  #lm-store .lm-image-wrap {
    height: 205px;
    padding: 12px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: #fff;
  }

  #lm-store .lm-image {
    width: 100%;
    height: 100%;
    object-fit: contain;
  }

  #lm-store .lm-no-image {
    color: #999;
    font-size: 13px;
  }

  #lm-store .lm-card-body {
    display: flex;
    flex-direction: column;
    flex: 1;
    padding: 14px;
  }

  #lm-store .lm-category-tag {
    align-self: flex-start;
    padding: 4px 8px;
    background: #fff0e5;
    color: #99400b;
    border-radius: 5px;
    font-size: 11px;
    margin-bottom: 8px;
  }

  #lm-store .lm-title {
    font-size: 15px;
    line-height: 1.45;
    margin: 0 0 8px;
    overflow-wrap: anywhere;
  }

  #lm-store .lm-description {
    color: var(--lm-muted);
    font-size: 13px;
    margin: 0 0 12px;
    overflow-wrap: anywhere;
  }

  #lm-store .lm-price-row {
    margin-top: auto;
    margin-bottom: 12px;
  }

  #lm-store .lm-price {
    font-size: 21px;
    font-weight: 800;
    color: #d9530a;
  }

  #lm-store .lm-old-price {
    font-size: 12px;
    color: var(--lm-muted);
    text-decoration: line-through;
    margin-left: 6px;
  }

  #lm-store .lm-rating {
    font-size: 12px;
    color: #555;
    margin-bottom: 12px;
  }

  #lm-store .lm-buy {
    width: 100%;
    margin-top: auto;
  }

  #lm-store .lm-buy:hover,
  #lm-store .lm-hero-btn:hover {
    background: #d95b13;
  }

  #lm-store #lm-status {
    color: var(--lm-muted);
    font-size: 14px;
    margin: 14px 0;
  }

  #lm-store .lm-empty {
    grid-column: 1 / -1;
    padding: 28px;
    text-align: center;
    border: 1px dashed #ccc;
    border-radius: 10px;
  }

  #lm-store .lm-footer {
    border-top: 1px solid var(--lm-line);
    margin-top: 40px;
    padding: 24px 8px;
    font-size: 13px;
  }

  #lm-store .lm-disclosure {
    color: var(--lm-muted);
  }

  @media (max-width: 900px) {
    #lm-store .lm-grid {
      grid-template-columns: repeat(3, minmax(0, 1fr));
    }
  }

  @media (max-width: 650px) {
    #lm-store .lm-toolbar {
      grid-template-columns: 1fr;
    }

    #lm-store .lm-grid {
      grid-template-columns: repeat(2, minmax(0, 1fr));
      gap: 10px;
    }

    #lm-store .lm-image-wrap {
      height: 155px;
    }

    #lm-store .lm-card-body {
      padding: 10px;
    }

    #lm-store .lm-title {
      font-size: 14px;
    }

    #lm-store .lm-price {
      font-size: 18px;
    }

    #lm-store .lm-hero {
      padding: 34px 16px;
    }
  }

  @media (max-width: 360px) {
    #lm-store .lm-grid {
      grid-template-columns: 1fr;
    }
  }
</style>

<script src="https://cdn.jsdelivr.net/npm/papaparse@5.4.1/papaparse.min.js"></script>

<script>
(function () {
  "use strict";

  // Replace with the published CSV URL from Google Sheets.
  const CSV_URL = "PASTE_YOUR_PUBLISHED_CSV_URL_HERE";

  const root = document.getElementById("lm-store");
  if (!root || root.dataset.initialized === "true") return;
  root.dataset.initialized = "true";

  const searchInput = root.querySelector("#lm-search");
  const categorySelect = root.querySelector("#lm-category");
  const sortSelect = root.querySelector("#lm-sort");
  const grid = root.querySelector("#lm-products");
  const status = root.querySelector("#lm-status");
  const count = root.querySelector("#lm-count");

  let products = [];

  function text(value) {
    return String(value == null ? "" : value).trim();
  }

  function safeUrl(value) {
    try {
      const url = new URL(text(value));
      if (url.protocol !== "https:" && url.protocol !== "http:") {
        return "";
      }
      return url.href;
    } catch (_) {
      return "";
    }
  }

  function priceOf(product) {
    const raw = text(product.price).replace(/,/g, "");
    if (!raw) return NaN;
    const value = Number(raw);
    return Number.isFinite(value) && value >= 0 ? value : NaN;
  }

  function formatPrice(product) {
    const value = priceOf(product);
    if (!Number.isFinite(value)) return "";

    const currency = text(product.currency) || "PHP";
    try {
      return new Intl.NumberFormat("en-PH", {
        style: "currency",
        currency: currency,
        maximumFractionDigits: 2
      }).format(value);
    } catch (_) {
      return currency + " " + value.toFixed(2);
    }
  }

  function addText(parent, tag, className, value) {
    const element = document.createElement(tag);
    if (className) element.className = className;
    element.textContent = value;
    parent.appendChild(element);
    return element;
  }

  function renderCard(product) {
    const card = document.createElement("article");
    card.className = "lm-card";

    const imageWrap = document.createElement("div");
    imageWrap.className = "lm-image-wrap";

    const imageUrl = safeUrl(product.image_url);

    if (imageUrl) {
      const image = document.createElement("img");
      image.className = "lm-image";
      image.src = imageUrl;
      image.alt = text(product.title);
      image.loading = "lazy";
      image.referrerPolicy = "no-referrer";
      image.onerror = function () {
        const fallback = document.createElement("span");
        fallback.className = "lm-no-image";
        fallback.textContent = "Image unavailable";
        image.replaceWith(fallback);
      };
      imageWrap.appendChild(image);
    } else {
      addText(imageWrap, "span", "lm-no-image", "Image unavailable");
    }

    card.appendChild(imageWrap);

    const body = document.createElement("div");
    body.className = "lm-card-body";

    const category = text(product.category);
    if (category) {
      addText(body, "span", "lm-category-tag", category);
    }

    addText(body, "h3", "lm-title", text(product.title));

    const description = text(product.description);
    if (description) {
      addText(body, "p", "lm-description", description);
    }

    const rating = Number(text(product.rating));
    const reviews = Number(text(product.review_count));

    if (Number.isFinite(rating) && rating > 0 && rating <= 5) {
      let label = "★ " + rating.toFixed(1);
      if (Number.isFinite(reviews) && reviews >= 0 &&
          text(product.review_count) !== "") {
        label += " (" + Math.floor(reviews).toLocaleString("en-PH") +
          " reviews)";
      }
      addText(body, "div", "lm-rating", label);
    }

    const priceRow = document.createElement("div");
    priceRow.className = "lm-price-row";

    const currentPrice = formatPrice(product);
    if (currentPrice) {
      addText(priceRow, "span", "lm-price", currentPrice);
    }

    const oldPriceValue = Number(
      text(product.original_price).replace(/,/g, "")
    );

    if (Number.isFinite(oldPriceValue) &&
        oldPriceValue > priceOf(product)) {
      let oldPriceText = "";
      try {
        oldPriceText = new Intl.NumberFormat("en-PH", {
          style: "currency",
          currency: text(product.currency) || "PHP",
          maximumFractionDigits: 2
        }).format(oldPriceValue);
      } catch (_) {
        oldPriceText = (text(product.currency) || "PHP") +
          " " + oldPriceValue.toFixed(2);
      }
      addText(priceRow, "span", "lm-old-price", oldPriceText);
    }

    body.appendChild(priceRow);

    const affiliateUrl = safeUrl(product.affiliate_url);
    if (affiliateUrl) {
      const button = document.createElement("a");
      button.className = "lm-buy";
      button.href = affiliateUrl;
      button.target = "_blank";
      button.rel = "sponsored nofollow noopener noreferrer";
      button.textContent = "View Deal";
      body.appendChild(button);
    }

    card.appendChild(body);
    return card;
  }

  function render() {
    const query = text(searchInput.value).toLocaleLowerCase();
    const category = categorySelect.value;
    const sort = sortSelect.value;

    let visible = products.filter(function (product) {
      const haystack = [
        product.title,
        product.category,
        product.description
      ].map(text).join(" ").toLocaleLowerCase();

      return (!query || haystack.includes(query)) &&
        (!category || text(product.category) === category);
    });

    if (sort === "price-asc") {
      visible.sort((a, b) => {
        const pa = priceOf(a), pb = priceOf(b);
        if (!Number.isFinite(pa)) return 1;
        if (!Number.isFinite(pb)) return -1;
        return pa - pb;
      });
    } else if (sort === "price-desc") {
      visible.sort((a, b) => {
        const pa = priceOf(a), pb = priceOf(b);
        if (!Number.isFinite(pa)) return 1;
        if (!Number.isFinite(pb)) return -1;
        return pb - pa;
      });
    } else if (sort === "name-asc") {
      visible.sort((a, b) =>
        text(a.title).localeCompare(text(b.title))
      );
    }

    grid.replaceChildren();
    visible.forEach(product => grid.appendChild(renderCard(product)));

    count.textContent = visible.length + " product" +
      (visible.length === 1 ? "" : "s");

    status.textContent = visible.length
      ? "Showing matching products."
      : "No products match your search. Try another keyword or category.";

    if (!visible.length) {
      addText(grid, "div", "lm-empty",
        "No products found. Please try different filters.");
    }
  }

  function showError(message) {
    status.textContent = message;
    count.textContent = "Catalog unavailable";
    grid.replaceChildren();
  }

  searchInput.addEventListener("input", render);
  categorySelect.addEventListener("change", render);
  sortSelect.addEventListener("change", render);

  if (CSV_URL.indexOf("PASTE_YOUR_") !== -1) {
    showError("Setup needed: replace CSV_URL with your published Google Sheets CSV URL.");
    return;
  }

  if (!window.Papa) {
    showError("The CSV library could not load. Please try again later.");
    return;
  }

  Papa.parse(CSV_URL, {
    download: true,
    header: true,
    skipEmptyLines: "greedy",
    transformHeader: function (header) {
      return text(header).replace(/^\uFEFF/, "");
    },
    complete: function (result) {
      if (result.errors && result.errors.length) {
        console.warn("CSV parsing warnings:", result.errors);
      }

      products = result.data.filter(function (product) {
        return text(product.title) && safeUrl(product.affiliate_url);
      });

      if (!products.length) {
        showError("No valid products found. Check your CSV headings and affiliate_url values.");
        return;
      }

      const categories = [...new Set(
        products.map(p => text(p.category)).filter(Boolean)
      )].sort((a, b) => a.localeCompare(b));

      categories.forEach(function (category) {
        const option = document.createElement("option");
        option.value = category;
        option.textContent = category;
        categorySelect.appendChild(option);
      });

      render();
    },
    error: function (error) {
      console.error("Catalog loading error:", error);
      showError("Could not load the catalog. Check the published CSV URL and access settings.");
    }
  });
})();
</script>

What this code does

  • Search: matches product titles, categories, and descriptions as you type.

  • Category filter: builds the category list from your CSV.

  • Price sorting: orders products from low to high or high to low, with a name-sorting option.

  • Product cards: display the image, title, description, price, and available ratings.

  • Affiliate tracking: the View Deal button opens the product's affiliate_url, not the ordinary product URL.

  • Responsive layout: uses four columns on wide screens and adapts to smaller screens.

The code uses DOM text insertion for product information rather than treating CSV values as HTML, which helps prevent product descriptions from injecting markup into the page.

Step 4 — Publish and test

  1. Save the page as a draft first. Confirm that the Blogger HTML editor accepts the code and doesn't remove the JavaScript.

  2. Check the catalog URL. Make sure the published CSV contains the exact column names and at least one valid affiliate_url for a product.

  3. Preview the page. Confirm that the products load and the search, category filter, and price sorting work.

  4. Test a View Deal button. Verify that it redirects through your own Involve Asia tracking link and reaches the intended Lazada product page.

  5. Test on mobile. Check the layout, image loading, search input, and category selector on a phone-sized screen.

  6. Publish the page. Add a Shop link to your Blogger navigation so visitors can find the storefront.

If the CSV fails to load, a common cause is a published URL that returns a webpage instead of CSV data, or a cross-origin request restriction. Blogger also supports adding HTML through its theme editor if you need to move the code out of the page editor.

Google Docs Editors Help
+1

Step 5 — Maintain your affiliate store

Your ongoing workflow will be:

Update Google Sheets

Add products, correct prices, update image URLs, and remove expired listings.

Verify affiliate links

Check that Involve Asia links are active and lead to the intended product pages. Check the offer's deeplinking rules and promotional guidelines.

Refresh and test

Reload the storefront after updating the published sheet and verify the new data.

Involve Asia provides a dashboard for monitoring affiliate performance and identifying broken or inactive links.

Involve Asia
+1

A few important limitations: this is an affiliate storefront, not a checkout system. Purchases, payments, shipping, and returns remain with Lazada. The current code reads the CSV when the page loads; it does not automatically scrape Lazada or guarantee real-time prices.

Your next milestone is to replace the sample data with real products, publish the Google Sheet, insert its URL in the code, and test the storefront before sharing it publicly.

Post a Comment

0 Comments