Category: Engineering

  • WooCommerce Speed Optimization: How We Got from 4 Seconds to 0.3 Seconds

    Back to Blog
    Engineering April 2026 · 6 min read

    WooCommerce Speed Optimization: How We Got from 4 Seconds to 0.3 Seconds

    We cut zamanistore.com’s mobile load time from 4.1 seconds to 0.31 seconds on shared cPanel hosting. No VPS migration, no expensive infrastructure. Here is exactly what we changed.

    Most WooCommerce speed guides tell you to upgrade your hosting. That advice is usually wrong. The problems are architectural, and they will follow you to a VPS if you do not fix them first. We proved this by hitting 0.31 seconds on a shared cPanel server that costs $15/month.

    zamanistore.com serves 12,000+ customers across 40+ countries in 26 currencies. A slow store in that context is not just an annoyance. It is a conversion problem with a direct AED value. These are the five changes that made the biggest difference.

    Step 1: Replace Your Theme’s CSS Framework

    Our WoodMart theme loaded Bootstrap 5 as its base CSS framework. That is 148KB of minified CSS containing a full grid system, 60+ utility classes, and component styles for accordions, modals, and carousels we were not using.

    We ran a CSS coverage audit in Chrome DevTools on a product page and found 23 CSS classes actively being applied out of 1,100+ defined in Bootstrap. We wrote a custom 12KB stylesheet that covered only those 23 patterns: the product layout grid, the cart drawer, the filter sidebar, and the header. CSS payload dropped 91%.

    The same logic applies to JavaScript. jQuery (87KB) was present for one accordion component. Six lines of vanilla JavaScript replaced it entirely.

    Do this first. A bloated CSS and JavaScript baseline will neutralize every caching improvement you make downstream.

    Step 2: Currency-Aware Edge Caching with Cloudflare

    Standard page caching tutorials tell you to install WP Rocket or W3 Total Cache. These work for single-currency stores. They break WooCommerce multi-currency because prices change per visitor. If you cache the AED version and serve it to a USD customer, they see wrong prices.

    We solved this with a custom Cloudflare Worker that caches HTML per currency code. When a visitor lands on a product page, the Worker checks their currency (set in a cookie on first visit), looks up the cached HTML for that currency, and serves it from Cloudflare’s edge network. The request never reaches our server for repeat visitors.

    Cache hit rate for repeat visitors: 94%. Return visit TTFB: 0.05 seconds. That is not a performance win. That is effectively instant from the customer’s perspective.

    This is how you achieve sub-second load times on shared hosting. The server processes 6% of traffic. The other 94% is answered from Cloudflare’s edge before the packet reaches your origin.

    Step 3: Convert All Product Images to WebP

    WooCommerce product images default to JPEG. A typical product gallery on zamanistore.com loaded 2.1MB of images on desktop. WebP achieves 30–50% smaller file sizes than JPEG at equivalent visual quality.

    We bulk-converted all product images to WebP (lossless for hero images, 80% quality for thumbnails), added proper srcset attributes for mobile and desktop breakpoints, and implemented lazy loading for images below the fold. Average image payload per product page dropped from 2.1MB to 340KB.

    WebP support is now at 97% of browsers globally. There is no meaningful reason to still serve JPEG for new product images.

    Step 4: Async-Load CSS and Defer JavaScript

    WooCommerce loads several CSS files that block rendering by default: the main theme stylesheet, WooCommerce core styles, and theme variant styles. None of these need to block the first paint. The page can begin rendering before they finish downloading.

    We moved them to load asynchronously using rel="preload" as="style" with an onload callback to swap to rel="stylesheet". For JavaScript, we deferred everything that is not required for above-the-fold interaction.

    This change alone dropped First Contentful Paint from 4.1 seconds to 1.9 seconds before any caching was applied.

    Step 5: Remove Database Bloat (Carefully)

    WooCommerce accumulates garbage in wp_options and wp_postmeta over time: expired transients, auto-draft posts, orphaned product meta, and plugin remnants. Our database had grown to 1.9GB, almost entirely from accumulated bloat.

    After removing expired transients, orphaned order meta, and auto-draft posts, the database dropped to 380MB. Average DB query time per page request went from 180ms to 22ms.

    Warning: Never run wp transient delete --all on a live WooCommerce store. It deletes WCML pricing transients and causes incorrect prices in the cart. Export a list of transients first, delete only expired ones, and test the cart immediately after.

    The Full Results

    Metric Before After
    First visit, mobile (FCP) 4.1s 0.31s
    Return visit (TTFB) 4.1s 0.05s
    CSS payload 148KB (Bootstrap) 12KB (custom)
    Image payload per page 2.1MB (JPEG) 340KB (WebP)
    Database size 1.9GB 380MB
    DB query time per page 180ms 22ms
    PageSpeed Mobile score 31 94

    All of this is on shared cPanel hosting. No VPS, no CDN subscription beyond Cloudflare free tier, no specialized hardware.

    0.31s
    Mobile FCP
    91%
    CSS Reduction
    94%
    Cache Hit Rate
    26
    Currencies Served

    Free Tool

    How does your store score?

    Enter your store URL and get a free automated audit: speed, SEO, ad tracking, email deliverability, and security. Scored 0–100 with specific issues. Takes 60 seconds.

    Get Your Free Audit →
    Back to Blog
    Stay in the Loop

    Get insights on building e-commerce with AI

    Behind-the-scenes on how we build, scale, and automate across 40+ countries. No spam, just signal.

  • WooCommerce Multi-Currency: 5 Mistakes and How to Fix Them

    WooCommerce Multi-Currency: 5 Mistakes and How to Fix Them

    TL;DR: We run zamanistore.com across 26 countries with 26 currencies using WCML. These 5 mistakes each caused real financial or customer experience damage before we fixed them: wrong prices served from cache, Stripe receiving wrong currency amounts, stale exchange rates silently eroding margins, coupons giving away more than intended, and new visitors seeing the wrong currency on their first visit.

    WooCommerce Multilingual (WCML) is the most robust multi-currency solution for WooCommerce. It integrates with WPML, handles translation, and supports complex pricing rules. But it has several non-obvious configuration requirements that cause real problems in production.

    These 5 mistakes are ordered by financial impact. Mistakes 1 and 2 are the most expensive. Mistakes 4 and 5 are the most common among stores that set up WCML themselves without guidance.

    The 5 Mistakes

    1
    Caching Without Currency Awareness
    Critical

    WP Rocket, Cloudflare, and most CDNs cache one version of each page by default. If a UAE visitor is the first to load your homepage, their AED-priced version gets cached. The next visitor from the UK gets the cached page with AED prices. No error, no warning — just the wrong number.

    This is the most common issue on stores that add a CDN after launching multi-currency. The store worked fine before the CDN, then suddenly customers start complaining about prices.

    WP Rocket: Add wcml_client_currency to the “Never Cache Cookies” field. This forces WP Rocket to serve separate cached versions per currency. Performance drops slightly (more cache variants), but prices are correct.

    Cloudflare: A Cloudflare Worker that reads the wcml_client_currency cookie and builds currency-specific cache keys is the better solution. It keeps performance high while serving the right variant. The cache key looks like: /product/keffiyeh/?_cf_currency=AED. Each currency gets its own edge cache entry. At zamanistore.com with 26 currencies and ~100 pages, that is about 2,600 cache entries per Cloudflare PoP.

    Fix: Add wcml_client_currency to WP Rocket’s “Never Cache Cookies” list, or implement a currency-aware Cloudflare Worker with per-currency cache keys.
    2
    Payment Processor Receiving the Wrong Currency
    Critical

    WCML has a payment gateway settings section that most people miss. By default, Stripe and PayPal receive the charge in your store’s base currency, not the customer’s currency. A customer in the UK sees £42 in the cart. Stripe charges them AED 42 (about £8.70). The payment succeeds, you get an underpayment, and you find out when reconciling statements.

    More commonly: Stripe returns an error because the currency combination is not supported (some currencies cannot be charged in certain countries). The checkout fails silently, or the customer sees a generic error and abandons.

    Go to WCML > Payments. For each gateway, set the currency to “Customer’s currency.” For Stripe, you also need to confirm your Stripe account supports payouts in each currency you sell in — not all do. A Stripe account in the UAE cannot receive payouts in GBP without enabling the feature.

    Fix: WCML > Payments > set each gateway to “Customer’s currency.” Verify Stripe account supports payouts for each active currency.
    3
    Manual Exchange Rates That Go Stale
    High

    WCML allows manual exchange rate entry. Most stores do this once at setup and never update it. Over 6-12 months, major currency pairs move 5-15%. A store with AED as the base currency that set the USD rate at 3.67 in 2024 and never updated it is now selling to US customers at rates that may be off by $3-5 on a $40 product.

    You are not always losing money — currency movement goes both ways. But you have no control, no visibility, and no ability to price intentionally by market when rates are hardcoded and stale.

    The fix is automatic rate refresh. WPML/WCML supports external exchange rate APIs. Open Exchange Rates (free tier: 1,000 requests/month) and fixer.io are both reliable. Set the refresh interval to daily. The rates will never be more than 24 hours stale, and your prices will track actual market rates without manual intervention.

    Fix: WCML > Currencies > set automatic exchange rate to “Open Exchange Rates” or “fixer.io” with daily refresh. Enter your API key in the settings.
    4
    Coupons That Do Not Convert by Currency
    High

    WooCommerce stores coupon discount amounts in your base currency. A coupon for “20 AED off” is stored as the number 20. When a US customer applies it, they get $20 off instead of the ~$5.45 equivalent. If your coupon is “10% off,” this is not an issue — percentage discounts are currency-agnostic. But if you use fixed-amount coupons for promotions, abandoned cart recovery, or referral rewards, you are giving away more than you intend in non-AED markets.

    WCML has a coupon currency conversion setting that applies the exchange rate automatically. The coupon value stays as 20 AED in the database, but the checkout displays and deducts the correct converted amount per customer currency.

    The other approach is to create currency-specific coupons: one for AED, one for USD, one for GBP, each with the correctly converted value. This is more work but gives you precise control over the discount in each market, independent of exchange rate fluctuations.

    Fix: WCML > Coupons > enable “Convert coupon amounts to customer’s currency.” Or create per-currency coupon codes with manually set values per market.
    5
    The First-Visit Edge Case
    Medium

    A new visitor from the UK lands on your site for the first time. They have no wcml_client_currency cookie yet. WCML needs to run its geolocation logic, set the cookie to GBP, and serve the right prices. This is all correct behavior — on the first request.

    The problem: if your Cloudflare cache (or WP Rocket, or any CDN) serves a cached page to this visitor before WCML runs, the visitor gets cached AED prices, and WCML sets the GBP cookie against a page they are already looking at. They refresh, see GBP prices. But the first page they landed on had AED prices. Depending on where they were in checkout, this creates confusion or incorrect cart totals.

    The fix at the Cloudflare Worker level is to bypass cache entirely for requests with no wcml_client_currency cookie. Let the first visit always hit origin. Origin sets the cookie. Every subsequent visit (with the cookie) gets served from edge cache with the correct currency variant. The performance cost is one origin hit per new visitor per device — trivial.

    // Cloudflare Worker: bypass cache for first-time visitors const currency = request.cookies.get(‘wcml_client_currency’); if (!currency) { return fetch(request); // pass through to origin }
    Fix: In your Cloudflare Worker, check for the wcml_client_currency cookie before serving from cache. If missing, pass the request to origin. Cache only applies on subsequent visits when the currency cookie is present.

    The Mismatch You Will Not See Until It Is Too Late

    Even with all 5 fixes in place, a misconfigured cache rule or a WCML update can silently introduce currency mismatches. We built an n8n automation (WF38/WF39) that fires on every new order webhook and checks the billing country against the order currency. If a UK customer (billing country: GB) places an order in AED, the order is put on hold automatically and a Slack alert fires.

    This catches 2-4 mismatches per week across zamanistore.com and Coloring Palestine. Without it, each one would become a support ticket, a refund request, or — worst case — a Stripe dispute.

    Where to Start

    If you are running WCML on a live store, check these in order:

    1. Open a product page in a private browser window from a country different from your base currency country. What prices do you see? Are they in the right currency?
    2. Add a test product to cart and proceed to checkout in a foreign currency. What does Stripe or PayPal show as the charge amount and currency?
    3. Apply a flat-amount coupon in a non-base currency. Is the discount amount correct for that currency?

    These three tests take 10 minutes and will surface the most common issues immediately.

    Is your store showing the right prices in every country?

    Our free store health check audits your tracking, speed, SEO, and email setup in 60 seconds.

    Get your free audit

    One Bit Dispatch

    Engineering posts, workflow breakdowns, and case studies. No filler.

  • 8 n8n Workflows That Save 4 Hours a Day for E-Commerce Stores

    8 n8n Workflows That Save 4 Hours a Day for E-Commerce Stores

    TL;DR: We run 39+ n8n automations across zamanistore.com and Coloring Palestine. These 8 workflows handle the most time-consuming daily tasks: abandoned cart follow-up, failed payment recovery, currency mismatch detection, order fulfillment, competitor monitoring, customer health scoring, return handling, and ad creative generation. Together they save more than 4 hours of manual work every day.
    39+
    Active workflows
    4 hrs
    Saved per day
    26
    Countries automated

    n8n is a self-hosted workflow automation tool. It connects your WooCommerce store, Slack, Gmail, Postgres, and any API into automated sequences that run without you. Unlike Zapier, you host it yourself, so there are no per-task fees and no artificial limits.

    Here are the 8 workflows that deliver the most value for an e-commerce store doing meaningful volume. All of these are live on our stores.

    The 8 Workflows

    1
    Abandoned Cart Recovery
    Saves ~60 min/day

    WooCommerce fires a webhook when a customer starts checkout but does not complete. n8n catches it and queues the cart in Postgres. Three timed jobs then run: an email at T+4 hours (product reminder, no discount), a second email at T+24 hours (social proof + shipping reassurance), and a WhatsApp message at T+48 hours for carts over 150 AED only (10% one-time discount).

    Our recovery rate at zamanistore.com is 14%, compared to the 4-8% industry average for single-channel email. The WhatsApp step alone recovers 3.8% of carts that ignored both emails.

    Critical implementation detail: WhatsApp Business API requires explicit consent. Only message customers who opted in at checkout or in a previous order. Sending unsolicited WhatsApp messages risks your number being banned.

    Stack: WooCommerce webhook → n8n Postgres queue → Gmail API (T+4h, T+24h) → Twilio WhatsApp (T+48h, high-value only)
    2
    Failed Payment Recovery
    Saves ~30 min/day

    When an order moves to “failed” status in WooCommerce, n8n catches the webhook and sends a personalized recovery email within 5 minutes. The email includes a direct link back to the cart with items pre-loaded, a list of accepted payment methods, and a note that the items are still held for 24 hours.

    We run separate workflows for zamani and Coloring Palestine because the tone, currency, and support contact differ. Failed payment recovery is one of the highest-ROI automations — a failed order already had intent; it just needs one friction point removed.

    Stack: WooCommerce webhook (order.failed) → n8n → Gmail API (personalized email with cart recovery link)
    3
    Currency Mismatch Detector
    Saves ~45 min/day

    On a multi-currency store with Cloudflare edge caching, a misconfigured cache rule can serve a US visitor an order at AED prices, or a UAE visitor at GBP prices. The order completes, the customer pays the wrong amount, and you find out weeks later during a dispute.

    This workflow fires on every new order webhook. It checks the billing country against the order currency. If the country ships to UAE but the currency is USD, or the country is UK but the currency is AED, it puts the order on hold and posts a Slack alert with the order ID, country, and currency. A human reviews before fulfillment.

    We catch 2-4 mismatches per week across both stores. Without this workflow each one would mean a manual refund, a reorder, and sometimes a chargeback.

    Stack: WooCommerce webhook (order.created) → n8n logic check → WooCommerce API (set on-hold) → Slack DM + Gmail alert
    4
    Delivery Status Sync (Safety Net)
    Saves ~60 min/day

    Shipping carrier webhooks break. In March 2026, our SwftBox delivery webhook was silently broken for 14+ days. Over 400 orders sat in “processing” status after being delivered. Customers received no completion email, loyalty points were not awarded, and the WooCommerce dashboard showed zero completed orders that month.

    The safety net runs every 4 hours. It queries Postgres for orders that are still in “processing” status but have a tracking code and are older than 48 hours. For each one, it calls the carrier API directly to check delivery status. If the carrier confirms delivery, it marks the order complete in WooCommerce, updates Postgres, and sends a Slack summary.

    This workflow is the reason we discovered the 14-day outage. It is now a permanent fixture regardless of webhook health.

    Stack: n8n cron (every 4h) → Postgres query → SwftBox API → WooCommerce REST API (PATCH status) → Slack summary
    5
    Return Request Handler
    Saves ~30 min/day

    A customer submits a return request via a simple Typeform or embedded form. n8n receives the webhook, looks up the original order in WooCommerce to confirm it is within the return window, checks the reason against the return policy categories, and routes it. Approved returns get an automated confirmation email with return shipping instructions. Requests outside the policy window or with missing order IDs get a different email explaining why.

    The time saving is not in processing volume — it is in eliminating the back-and-forth of “what was your order number?”, “when did you order?”, “what is your reason?” An automated intake form that validates against the actual order cuts the average return resolution from 3 messages to 1.

    Stack: Form webhook → n8n → WooCommerce REST API (order lookup) → Gmail API (conditional email routing)
    6
    Competitor Price Monitor
    Saves ~30 min/day

    Every Friday at 8pm UAE time, n8n scrapes the product pages of the 3-5 main competitors in each product category. It stores the prices in Postgres with a timestamp. Then it compares this week’s prices to last week’s, calculates the delta, and posts a Slack report to #competitor-monitor with a table: competitor name, product, last week’s price, this week’s price, change percentage.

    Before this workflow, tracking competitor pricing meant manually visiting 15+ pages weekly. Now it is a 2-minute Slack read every Friday. The bigger value is catching when a competitor drops prices significantly — which is often a signal of a sale, an overstock situation, or a product discontinuation you can capitalize on.

    For scraping, n8n’s HTTP Request node with a rotating user-agent works for most simple product pages. For JavaScript-heavy pages, a headless Playwright instance behind an API endpoint is more reliable.

    Stack: n8n cron (Fri 8pm) → HTTP Request (scrape product pages) → Postgres (price history) → Claude (summarize changes) → Slack #competitor-monitor
    7
    Customer Health Report
    Saves ~20 min/day

    Every two weeks, n8n queries Postgres for customer cohort data: new customers this period vs. last, repeat purchase rate, average order value, top-selling products, geographic breakdown, and the 10 most recent reviews from Site Reviews. Claude writes a 200-word narrative summary comparing this period to the last one and highlighting 2-3 things worth acting on.

    The report goes to a private Slack channel. It takes 5 minutes to read and replaces what used to be 30 minutes of pulling Google Analytics, WooCommerce reports, and Site Reviews into a spreadsheet every other Monday.

    The key is keeping the output actionable. If the repeat purchase rate dropped, the report says so and names the specific cohort (e.g., UK customers who ordered in February). If a product had a spike in 1-star reviews this period, it flags the product name and review count.

    Stack: n8n cron (biweekly Mon 7am) → Postgres queries → Claude API (narrative summary) → Slack DM
    8
    Ad Creative Generator
    Saves ~45 min/day

    The most complex workflow we run. We submit a product photo and a brief to a form. n8n sends the image to Gemini for product description and visual analysis, uses that output to construct a script prompt, then calls Kling to generate a 5-second video ad with motion. The finished video is saved to Google Drive, and a Slack DM is sent with a preview link and the generated copy variants.

    From form submission to Slack notification is about 4 minutes. A single freelancer video shoot would take a week to brief, shoot, edit, and deliver. This workflow produces rough drafts good enough to test in Meta ads for around $0.10 per run.

    The videos are not broadcast quality. They work at the top of the funnel where fast production and volume matter more than polish. We use them to test angles before investing in professional production.

    Stack: Form webhook → n8n → Gemini (image analysis + copy) → Kling API (video generation) → Google Drive (storage) → Slack DM

    How to Get Started

    n8n runs on any VPS with Docker. The official Docker image is n8nio/n8n. On a $6/month VPS (2GB RAM), it handles 39 workflows without issue. Exposed only to localhost with Nginx reverse proxy and HTTP Basic Auth is the recommended production setup.

    Start with workflow 1 (abandoned cart) or workflow 2 (failed payment recovery). Both have immediate, measurable ROI and are simple enough to build in a few hours. Workflows 3 and 4 are more complex but critical if you run multi-currency or rely on third-party shipping carriers.

    The compound effect matters: each workflow runs in the background while you do something else. At 39 workflows, the daily hours saved exceeds what any single hire could do for the equivalent monthly cost.

    See how your store scores on automation

    Our free store health check audits your tracking setup, speed, SEO, and email deliverability in 60 seconds.

    Get your free audit

    One Bit Dispatch

    Engineering posts, workflow breakdowns, and case studies. No filler.

  • Abandoned Cart Recovery for WooCommerce: What Actually Works (With Numbers)

    Abandoned Cart Recovery for WooCommerce: What Actually Works (With Numbers)

    TL;DR: The average WooCommerce store recovers 4-8% of abandoned carts. Our sequence recovers 14%. The difference is not the discount — it is the timing, the channel mix (email + WhatsApp), and the content of the first message. This post breaks down the exact sequence we run on zamanistore.com.

    Most abandoned cart guides tell you to send three emails with increasing discount levels. That advice is 10 years old and it does not work as well as it used to. Browser privacy changes have reduced email open rates, and customers have learned to abandon carts specifically to wait for the discount email.

    We took a different approach. Instead of leading with discounts, we lead with information. And instead of only emailing, we use WhatsApp for high-value carts. Here is what our numbers look like after 12 months of running this system on zamanistore.com.

    14%
    Cart recovery rate (vs 4-8% average)
    4 hours
    Optimal delay for first touchpoint
    39+
    n8n automations running across our stores

    The Sequence That Works

    We use a 3-step sequence. No discount in steps 1 or 2. Discount only in step 3, and only for carts above a threshold value.

    Step Timing Channel Message angle Recovery rate (this step)
    1 4 hours after abandonment Email Product reminder, no pressure 6.2%
    2 24 hours Email Social proof + urgency (low stock) 4.1%
    3 48 hours (carts >150 AED only) WhatsApp 10% discount, personal tone 3.8%

    Total: 14.1% across all three steps. After step 3, we stop. Sending more messages hurts your sender reputation more than it helps.

    Step 1: The 4-Hour Email

    The biggest mistake in abandoned cart emails is sending too early or too late. Under one hour feels pushy and catches people who were still shopping. Over 24 hours and they have forgotten about it. Four hours is the sweet spot — long enough that the purchase feels considered, short enough that the product is still in mind.

    The first email has one job: remind them what they left behind. No discount language. No “you forgot something!” subject line. The subject line that works best for us is simply the product name.

    Content structure:

    1. Product name and image
    2. One sentence about the product (not marketing copy — something specific)
    3. Cart total and a single clear CTA: “Complete your order”
    4. Optional: 1-2 recent reviews for social proof
    Subject line that converts: “[Product name] is still in your cart” outperforms “You left something behind” by 23% in our tests. Being specific beats being clever.

    Step 2: The 24-Hour Social Proof Email

    By the 24-hour mark, a customer who has not purchased has likely seen the product, thought about it, and moved on. You need a reason for them to reconsider that is not a discount.

    Two angles work well:

    Low stock warning: If the product genuinely has under 10 units, include this. “Only 4 left in stock” is not a dark pattern if it is true. We only show stock counts when they are real and below 10.

    Social proof: Include 1-2 reviews from customers in the same country as the abandoner, if you have them. A review from someone in Riyadh lands differently than a generic five-star rating when you are targeting Saudi Arabia.

    Step 3: WhatsApp for High-Value Carts

    This is the part most WooCommerce stores skip, and it is where we get a disproportionate amount of our recovery.

    For carts above 150 AED (about $41), after 48 hours of no purchase, we send a WhatsApp message. We use Twilio for delivery. The message is short, personal in tone, and includes a one-time 10% discount code.

    Why WhatsApp works better than a third email: In the UAE, Saudi Arabia, and most of the Middle East, WhatsApp is the primary communication channel. Open rates are near 100%. A WhatsApp message from a brand feels more personal and less filterable than an email.

    Compliance note: WhatsApp Business API requires opt-in consent before sending marketing messages. Make sure your checkout collects phone number and explicit SMS/WhatsApp marketing consent before enabling this step. Without consent, you risk account suspension.

    The Technical Setup (n8n)

    We build this in n8n rather than using a plugin. Here is the architecture:

    1. WooCommerce webhook on woocommerce_checkout_order_created fires when a checkout is initiated but not completed.
    2. n8n stores the cart in Postgres with a timestamp and cart value.
    3. Scheduled triggers at T+4h and T+24h check Postgres for carts that have not converted and send the respective emails via Gmail API.
    4. T+48h trigger checks if cart value exceeds threshold and sends WhatsApp via Twilio if so.
    5. When an order completes, a woocommerce_order_status_completed webhook marks the Postgres record as converted so no further messages are sent.

    Total workflow: 4 n8n workflows (WF49a-d) handling approximately 200-400 abandoned carts per month across both stores. Zero manual intervention required after initial setup.

    What Does Not Work

    • Leading with a discount: Trains customers to abandon deliberately to get 10% off. We tested this — conversion rate goes up, average order value goes down, and repeat discount-hunters increase.
    • Four or five emails: After step 3, you are just burning your unsubscribe budget. Open rates on emails 4-5 drop below 5% and unsubscribe rates spike.
    • Generic subject lines: “You left something behind!” and “Your cart misses you” both underperform product-specific subject lines in every A/B test we have run.
    • Sending to all abandoned carts equally: A cart abandoned at step 1 of checkout (viewing cart) is different from one abandoned at the payment page. We only trigger the sequence for carts that reached the checkout form — intent is higher.

    Want this running on your store?

    The StoreOps Autopilot package includes the full abandoned cart recovery sequence (email + WhatsApp), order routing, and post-purchase automations. Start with a free store audit to see what your current setup is missing.

    Get Free Audit

    E-commerce ops, once a month.

    Automation workflows, ad setups, and store optimizations from building two brands across 26 countries. No fluff.

  • How to Set Up Facebook CAPI for WooCommerce and Shopify (2026)

    How to Set Up Facebook CAPI for WooCommerce and Shopify (2026)

    TL;DR: Facebook’s Conversions API (CAPI) sends purchase events directly from your server to Meta, bypassing iOS privacy restrictions and ad blockers. Without it, you are flying blind on 30-40% of your conversions. This guide covers the complete setup for both WooCommerce and Shopify, including the deduplication step most tutorials skip.

    iOS 14.5 shipped in April 2021 and changed e-commerce advertising permanently. Before it, the Meta Pixel tracked almost every purchase. After it, browser-side tracking dropped 30-40% on iOS devices — and that number has only grown as Safari, Firefox, and ad blockers have tightened further.

    The Meta Conversions API solves this by sending events from your server instead of the visitor’s browser. The server does not care about iOS privacy settings or ad blockers. It sends the Purchase event directly to Meta with hashed customer data, and Meta matches it to an ad click.

    We run CAPI across both zamani and Coloring Palestine. Here is exactly how we set it up — and the deduplication mistake most guides do not mention.

    30-40%
    iOS conversion signal lost without CAPI
    6+
    Target Event Match Quality score
    3 hours
    Typical setup time

    Step 1: Generate a Conversions API Access Token

    Go to Meta Business Suite, then Events Manager. Select the pixel attached to your store. Click the Settings tab. Scroll down to the “Conversions API” section and click Generate Access Token.

    Copy this token and store it somewhere secure — you will need it in the next step. Do not put it in your theme’s functions.php or anywhere that gets committed to version control.

    Which pixel to use: If you have multiple Meta pixels, use the one attached to your ad account. Events Manager shows which ad account each pixel is linked to. Using the wrong pixel means your CAPI events land in a different dataset from your browser pixel events — and deduplication breaks.

    Step 2: Install Server-Side Tracking on Your Store

    WooCommerce

    You have two paths:

    Option A — Plugin (easiest): PixelYourSite Pro has native CAPI support. Install it, paste your access token, and it handles Purchase, AddToCart, and InitiateCheckout server-side events automatically. It also handles event deduplication using its own event ID system.

    Option B — Custom n8n workflow (full control): This is what we use at One Bit. A WooCommerce webhook fires on woocommerce_payment_complete, sends order data to n8n, and n8n forwards a hashed CAPI Purchase event to Meta’s Graph API. More setup work, but you control exactly what data is sent and can add custom parameters.

    The Graph API endpoint for CAPI events is:

    POST https://graph.facebook.com/v21.0/{PIXEL_ID}/events
    Content-Type: application/json
    
    {
      "data": [{
        "event_name": "Purchase",
        "event_time": 1711929600,
        "event_id": "unique-uuid-here",
        "action_source": "website",
        "user_data": {
          "em": ["sha256_hashed_email"],
          "ph": ["sha256_hashed_phone"],
          "fn": ["sha256_hashed_first_name"],
          "ln": ["sha256_hashed_last_name"],
          "country": ["ae"],
          "zp": ["00000"]
        },
        "custom_data": {
          "currency": "AED",
          "value": 149.00,
          "content_ids": ["product-sku-123"],
          "content_type": "product"
        }
      }],
      "access_token": "YOUR_TOKEN_HERE"
    }

    Shopify

    Shopify has a native CAPI integration. Go to Settings > Customer events, click Add connection, and select Facebook. Choose your pixel. Enable “Send server events” and paste your access token.

    Shopify’s native integration covers the main purchase funnel: PageView, ViewContent, AddToCart, InitiateCheckout, Purchase. It handles hashing automatically.

    Shopify gotcha: The native integration only fires events for orders processed through Shopify Checkout. If you use a third-party checkout or headless commerce setup, you need a custom implementation.

    Step 3: Implement Event Deduplication

    This is the step most tutorials skip, and it causes real problems if you miss it.

    When you have both a browser pixel and CAPI running, every Purchase event fires twice — once in the browser, once from the server. Meta sees two Purchase events and counts them as two conversions. Your reported ROAS doubles. Your campaign data becomes useless.

    The fix is a unique event_id. Here is how it works:

    1. When a customer lands on your order confirmation page, generate a UUID: crypto.randomUUID() in JavaScript works fine.
    2. Fire the browser pixel with that UUID: fbq('track', 'Purchase', purchaseData, {eventID: 'your-uuid-here'});
    3. Send the same UUID in your server-side CAPI call in the event_id field.
    4. Meta receives both events with the same event_id and counts them as one.

    For WooCommerce with PixelYourSite: it handles this automatically. For custom n8n setups: generate the UUID on the thank-you page (JavaScript), store it in a session variable or pass it via a WooCommerce order meta field, then include it in the n8n CAPI call when the woocommerce_payment_complete hook fires.

    Step 4: Hash Customer Data Correctly

    CAPI matches events to Meta users using hashed PII. The matching happens on Meta’s side — you never send plain-text personal data. The fields Meta uses:

    • em — email (SHA-256, lowercase, trimmed)
    • ph — phone (SHA-256, E.164 format: +971501234567)
    • fn — first name (SHA-256, lowercase)
    • ln — last name (SHA-256, lowercase)
    • country — 2-letter ISO code (SHA-256, lowercase)
    • ct — city (SHA-256, lowercase, no spaces)
    • zp — zip/postal code (SHA-256)

    In PHP:

    $hashed_email = hash('sha256', strtolower(trim($customer_email)));
    $hashed_phone = hash('sha256', preg_replace('/[^0-9+]/', '', $phone));
    More fields = better match quality. Every additional hashed field improves your Event Match Quality score. For Middle East stores: always include country (ae, sa, kw, etc.) and phone. Phone matching is strong in this region since most customers use WhatsApp-linked numbers.

    Step 5: Test and Verify in Events Manager

    Before going live, use Meta’s test tool:

    1. In Events Manager, open your pixel and click Test Events.
    2. Copy the test event code (looks like TEST12345).
    3. Pass this code as test_event_code in your CAPI API call (remove it before going to production).
    4. Run a test purchase on your store.
    5. Confirm the event appears in Events Manager with source “Server” alongside the browser pixel event with source “Browser”.
    6. Verify both show the same event_id — this confirms deduplication is working.

    After you go live, check your Event Match Quality score (shown in Events Manager for each event type). A score below 6 means Meta cannot reliably match the event to a user — your CAPI data is underperforming. Common causes: missing phone field, not sending country, or email not trimmed/lowercased before hashing.

    Common Mistakes We See

    • No deduplication: Running browser pixel and CAPI without event IDs — ROAS appears doubled.
    • Wrong pixel ID: CAPI events land in a different dataset from browser pixel events — no deduplication possible.
    • Phone number format: Sending 0501234567 instead of +971501234567 — E.164 format is required for phone matching.
    • Test event code left in production: All production events land in test mode and are not counted in campaigns.
    • Missing currency: Always include currency and value in custom_data for Purchase events — without them, Meta cannot optimize for purchase value.

    Not sure if your CAPI is set up correctly?

    Get a free automated audit of your store’s ad tracking setup — we check for Facebook Pixel, GTM, GA4, and flag common configuration issues.

    Get Free Audit

    E-commerce ops, once a month.

    Automation workflows, ad setups, and store optimizations from building two brands across 26 countries. No fluff.

  • How We Monitor 20,000+ Orders Across 40 Countries Without a Dedicated Ops Team

    200+
    Customers Contacted in Minutes
    4
    Custom Tiers
    4.8
    Average Rating
    0
    Customers Asked First

    The Results

    Across our brands, we maintain a 4.8 average customer rating. Response times are measured in minutes, not hours. One small team manages operations for multiple brands shipping to over 40 countries.

    The key insight is that most operational work is not creative problem-solving. It is pattern recognition and execution. A currency mismatch follows a pattern. A shipping delay follows a pattern. Customer communication for each scenario follows a pattern. When you encode those patterns into automated systems, you free your team to focus on the genuinely novel problems that require human judgment.

    Building for Reliability

    We do not build these systems because automation is trendy. We build them because our customers deserve consistent, fast, proactive service regardless of whether it is Tuesday at 10 AM or Saturday at midnight. Automation does not sleep, does not forget edge cases, and does not have bad days.

    The goal is not to eliminate the human element. It is to make sure the human element is applied where it matters most: complex disputes, relationship-building with key accounts, and designing the next generation of systems. Everything else should run itself.

    Back to Blog
Stay in the Loop

Get insights on building culture-driven brands with AI

Behind-the-scenes on how we build, scale, and automate across 40+ countries. No spam, just signal.

  • From Form to Finished Ad: How AI Builds Our Video Campaigns

    $0.25
    Per Video Ad
    90s
    To Create
    3
    Platforms
    50+
    Variations Tested

    Why This Matters for Small Teams

    The conventional wisdom is that you need a creative department to compete with bigger brands. A designer. A copywriter. A video editor. A media buyer who knows what performs. That team costs $200,000 or more per year before you have run a single ad.

    Our approach inverts this. A small team armed with the right pipeline can out-experiment companies ten times their size. The competitive advantage is not in having better creative instincts. It is in testing so many variations so quickly that you find what works faster than anyone else can.

    When you can produce fifty ad variations in the time it takes a traditional team to produce three, you are not just saving money. You are operating in a fundamentally different way. You are running more experiments per week than most companies run per quarter.

    The Philosophy

    We do not replace creativity with AI. The creative decisions still matter: which product angles to test, which audiences to target, what tone resonates with a particular market. Those are human judgments.

    What AI removes is the bottleneck between having a creative idea and testing it with real customers. The gap between “what if we tried this angle?” and “here is the data” used to be weeks. Now it is hours.

    That speed changes everything. Not because AI is creative. Because it lets creative people move at the speed of their ideas.

    Back to Blog
    Stay in the Loop

    Get insights on building culture-driven brands with AI

    Behind-the-scenes on how we build, scale, and automate across 40+ countries. No spam, just signal.

  • How We Run Multiple Brands With a Small Team: Our Automation-First Approach

    39+
    Workflows
    24/7
    Monitoring
    <$0.25
    Per Ad
    40+
    Countries

    The Results

    Numbers tell the story better than philosophy:

    30+

    Countries served

    20,000+

    Orders processed

    Minutes

    Average response time

    Multiple

    Brands on one platform

    The real result is harder to quantify: our team spends their days on work they find meaningful. Nobody is copying data between spreadsheets. Nobody is manually checking order statuses. Nobody is pulling the same report for the third time this week. The machines handle the repetition. The humans handle the thinking.

    Looking Ahead

    We are building toward a future where launching a new brand takes weeks, not months. The infrastructure is already there: the monitoring, the automation, the customer communication systems, the advertising pipelines. Each new brand plugs into the existing foundation.

    The compounding effect is real. Every system we build makes the next one faster and cheaper. Every problem we solve once never needs solving again. This is what lets a small team compete with companies that have ten times the headcount.

    Automation is not about removing people from the equation. It is about giving people the leverage to do their best work. That is the One Bit approach, and we are just getting started.

    Interested in joining our team?

    We are always looking for people who think in systems.

    See Open Roles
    Stay in the Loop

    Get insights on building culture-driven brands with AI

    Behind-the-scenes on how we build, scale, and automate across 40+ countries. No spam, just signal.