How to Sync WooCommerce Product Reviews into Klaviyo Profile Properties

Build a scheduled Spojit workflow that pulls recent WooCommerce product reviews, matches each reviewer to their Klaviyo profile by email, and writes their latest review rating and sentiment as custom profile properties.

What This Integration Does

Product reviews are some of the richest first-party signals you collect, but they usually sit locked inside your store and never reach your marketing tools. This workflow lifts every new WooCommerce review out of the store, finds the matching customer in Klaviyo, and stamps their profile with their most recent rating and a sentiment label. Once those values live on the profile as custom properties, you can segment on them in Klaviyo: send a thank-you flow to five-star reviewers, route one and two-star reviewers into a win-back or support sequence, or suppress unhappy customers from promotional sends.

The workflow is driven by a Schedule trigger, so it runs on a fixed cadence (for example every morning) with no manual effort. On each run it reads reviews created since the last run, loops over them, looks each reviewer up in Klaviyo, and updates the matched profile. Each run is idempotent at the property level: writing the same rating and sentiment again simply overwrites the previous value, so a re-run never duplicates anything. Reviewers who do not yet have a Klaviyo profile are skipped cleanly rather than failing the run.

Prerequisites

  • A WooCommerce connection in Spojit with REST API read access to your store (so the workflow can read reviews and the products they belong to). See the WooCommerce connector article to set it up.
  • A Klaviyo connection with permission to read and update profiles. See the Klaviyo connector article.
  • Product reviews enabled on your WooCommerce store, with the reviewer email captured (the default WooCommerce review form captures it).
  • Two custom properties you intend to populate on Klaviyo profiles, for example latest_review_rating and latest_review_sentiment. Klaviyo creates custom properties automatically the first time you write them, so no setup is needed in Klaviyo itself.

Step 1: Start the workflow on a Schedule trigger

Add a Trigger node and set its type to Schedule. Schedules use a 5-field Unix cron expression plus an IANA timezone. To run once every morning at 6 AM Sydney time, use cron 0 6 * * * with timezone Australia/Sydney. The trigger output is { scheduledAt }, the timestamp the run was fired, which you will use to bound the review query.

Pick a cadence that comfortably covers your review volume. A daily run is plenty for most stores; a busy store can run hourly with 0 * * * *. A single trigger can hold multiple schedules if you want different cadences.

Step 2: Compute the lookback window

Add a Connector node using the date utility connector in Direct mode, and choose the subtract tool to build the "reviews after this time" boundary. Subtract your interval (for example 1 day, or 25 hours to give a small overlap that avoids missing reviews on the boundary) from {{ trigger.scheduledAt }}. Format the result as an ISO 8601 timestamp; WooCommerce expects review dates in that form. Store the output as after so later steps can reference {{ after }}.

A short overlap window is safer than an exact one. Because the property write is an overwrite, re-processing a review you already handled is harmless, so erring on the side of a wider window costs nothing.

Step 3: Fetch recent reviews from WooCommerce

Add a Connector node for the woocommerce connector in Direct mode. WooCommerce reviews are served by the store REST API, so select the raw-api-request tool. Set method to GET and path to the product reviews endpoint with query parameters for ordering and your lookback boundary:

method: GET
path: /products/reviews?after={{ after }}&orderby=date&order=desc&per_page=50&status=approved

This returns approved reviews created after your boundary, newest first. Each review object includes the fields you need downstream, notably reviewer_email, rating (1 to 5), review (the comment text), product_id, and date_created. Save the result as reviews.

If your store has more than 50 new reviews in a single window, raise per_page (WooCommerce caps it at 100) or shorten the schedule interval so each run handles a smaller batch.

Step 4: Loop over each review

Add a Loop node in ForEach mode and point it at {{ reviews }} (the array returned by the previous step). Everything inside the loop body runs once per review, with the current item available as the loop variable, for example {{ review }}. This is where you match the reviewer and update their profile.

Keep the loop body lean: a lookup, a branch, and a single update. If you anticipate large batches, you can instead fan reviews out with a Parallel node, but a sequential ForEach loop is simpler and stays well within Klaviyo rate limits.

Step 5: Find the matching Klaviyo profile

Inside the loop, add a Connector node for the klaviyo connector in Direct mode and choose the list-profiles tool. Klaviyo filters use JSON:API syntax, so match on the reviewer email exactly:

filter: equals(email,"{{ review.reviewer_email }}")
pageSize: 1

If the reviewer exists in Klaviyo, the response contains one profile whose ID you can read as {{ profile.data[0].id }}. If there is no match, the data array comes back empty. Save the output as profile.

Step 6: Skip reviewers with no profile

Add a Condition node that checks whether a profile was found, for example testing that {{ profile.data[0].id }} is not empty. Route the false branch to nothing (the loop simply moves on to the next review), and route the true branch into the update step. This keeps the workflow from failing when a reviewer has never been added to Klaviyo, which is common for guest checkouts.

Optionally, on the true branch you can derive a sentiment label before updating. Add a Transform node that maps the numeric {{ review.rating }} to a string: 4 or 5 becomes positive, 3 becomes neutral, and 1 or 2 becomes negative. Store it as sentiment. For richer sentiment from the comment text itself, you could instead use a Connector node in Agent mode with a Response Schema, but a rating-based mapping is deterministic and free.

Step 7: Write the review properties to the profile

On the true branch, add a Connector node for the klaviyo connector in Direct mode and choose the update-profile tool. Pass the matched profile ID and an attributes object that nests your review fields under properties (custom properties always live there in Klaviyo):

id: {{ profile.data[0].id }}
attributes:
{
  "properties": {
    "latest_review_rating": {{ review.rating }},
    "latest_review_sentiment": "{{ sentiment }}",
    "latest_review_product_id": {{ review.product_id }},
    "latest_review_date": "{{ review.date_created }}"
  }
}

Klaviyo merges these into the existing profile, so other properties are untouched and the named ones are overwritten with the latest values. The loop then continues to the next review. After the workflow is built, enable it so the schedule starts firing.

Tips

  • Use Spojit's Miraxa, the intelligent layer across your automation, to scaffold the skeleton fast. Try a prompt like "Build a workflow on a daily Schedule trigger that fetches WooCommerce product reviews with the woocommerce raw-api-request tool, loops over them, looks each reviewer up in Klaviyo with list-profiles, and updates the matched profile with update-profile." Then fine-tune the fields in the properties panel.
  • Store more than one field at once. Writing the product ID and review date alongside the rating lets you build Klaviyo segments like "left a 5-star review in the last 30 days" without another sync.
  • Keep your lookback window slightly wider than the schedule interval (Step 2). Because property writes are overwrites, a small overlap protects against boundary gaps with no downside.
  • If you only care about negative reviews for an escalation flow, add a second Condition after the sentiment Transform and skip the update for positive ratings.

Common Pitfalls

  • Timezone drift: the Schedule trigger fires in the timezone you set, but WooCommerce stores review dates in the store timezone. Build the after boundary consistently (Step 2) and verify the first few runs against real review timestamps so you do not miss or double-read the edge.
  • Guest reviewers with no profile: many reviews come from guest checkouts that were never added to Klaviyo. The Condition in Step 6 is required; without it the run fails the moment it hits an unmatched email.
  • Properties nesting: Klaviyo custom properties must be nested under properties inside attributes. Writing them at the top level of attributes targets standard fields and your custom values will not appear where you expect.
  • Pagination on busy stores: raw-api-request returns one page. If a single window can exceed per_page reviews, either raise the page size to 100, shorten the schedule, or follow WooCommerce paging headers to read the next page before the loop.

Testing

Before enabling the schedule, validate on a tiny scope. Temporarily narrow the WooCommerce query in Step 3 to a single known product (add &product={{ productId }} to the path) or widen after to a date you know has a handful of reviews, then use the Run button to fire the workflow once. Open the run in execution history and confirm the reviews array is populated, the Klaviyo list-profiles lookup returns the right profile ID, the Condition routes guests away cleanly, and update-profile returns the updated profile. Check the profile in Klaviyo to confirm latest_review_rating and latest_review_sentiment are present, then restore the full query and enable the schedule.

Learn More

Did this answer your question? Thanks for the feedback There was a problem submitting your feedback. Please try again later.