Refunds Issued
Also known as: Refund Count, Number of Refunds, Refund Transactions, Refunds Processed, Refunds
Count of distinct refund transactions, full or partial, issued to customers in the period by refund date. It counts refunds, not their value, and is the numerator of Refund Rate.
Business Use Case
1️⃣ Customer Service sees a weekly refund spike, splits it by return reason and escalates the top SKUs to Merchandising.,2️⃣ Finance matches the refund count to payment processor settlements at month-end before closing the refund accrual.,3️⃣ Merchandising tracks refunds by item category after a supplier change and pulls lines whose count keeps rising.
Business Criticality
High
Journey / Navigation Area
Monetization
Owning Function
Customer Service
Scope
Event
Formula
Calculation Notes
1️⃣ One count per refund_id; several partial refunds on one order count separately, and resends of the same refund_id count once.,2️⃣ Dated by refund issue date, not order date; a refund on an order from a prior period counts in the period it is issued.,3️⃣ Full and partial refunds both count; split them with refund_type rather than excluding either.,4️⃣ Counted when the refund is issued, not when a return is initiated or approved; pending refunds wait until they are issued.,5️⃣ Excludes voided authorisations with no captured funds, chargebacks and test orders; none is a merchant-issued refund.,6️⃣ The refund event is usually sent server-side; reconcile weekly against platform refund records, as dropped hits leave gaps.
Technical Details
Events
| Platform | Event |
|---|---|
| Google Analytics 4 | refund |
| Adobe | refund |
Data Mappings
W3 Data Layer
{
"transaction": {
"transactionID": "txn-1",
"total": {
"transactionTotal": 100,
"currency": "USD"
},
"attributes": {
"refundID": "rfd-1",
"refundType": "partial",
"trafficType": "external"
}
},
"event": [
{
"eventInfo": {
"eventName": "refund"
}
}
]
}GA4 Data Layer
{
"event": "refund",
"refund_id": "rfd-1",
"refund_type": "partial",
"traffic_type": "external",
"ecommerce": {
"transaction_id": "txn-1",
"currency": "USD",
"value": 100,
"items": [
{
"item_id": "SKU-1",
"item_name": "item",
"price": 100,
"quantity": 1
}
]
}
}Adobe Client Data Layer
{
"event": "refund",
"eventInfo": {
"refundID": "rfd-1",
"refundType": "partial",
"refundAmount": 100,
"trafficType": "external"
},
"commerce": {
"order": {
"purchaseID": "txn-1",
"currencyCode": "USD"
}
},
"productListItems": [
{
"SKU": "SKU-1",
"quantity": 1,
"priceTotal": 100
}
]
}XDM Mapping
{
"eventType": "refund",
"identityMap": {
"ECID": [
{
"id": "ecid-1",
"authenticatedState": "ambiguous",
"primary": true
}
]
},
"commerce": {
"order": {
"purchaseID": "txn-1",
"currencyCode": "USD"
}
},
"productListItems": [
{
"SKU": "SKU-1",
"quantity": 1,
"priceTotal": 100
}
],
"_tenantId": {
"trafficType": "external",
"refund": {
"refundID": "rfd-1",
"refundType": "partial",
"refundAmount": 100
}
}
}SQL Queries
Google Analytics 4 (BigQuery)
-- ==========================================
-- 1. GOOGLE BIGQUERY SQL
-- ==========================================
DECLARE start_date DATE DEFAULT DATE_SUB(CURRENT_DATE(), INTERVAL 90 DAY);
DECLARE end_date DATE DEFAULT DATE_SUB(CURRENT_DATE(), INTERVAL 1 DAY);
-- Refund events in the period with refund_id, traffic_type and refunded value pivoted from event_params
WITH refunds AS (
SELECT
MAX(IF(ep.key = 'refund_id', ep.value.string_value, NULL)) AS refund_id,
MAX(IF(ep.key = 'traffic_type', ep.value.string_value, NULL)) AS traffic_type,
MAX(IF(ep.key = 'value', COALESCE(ep.value.double_value, CAST(ep.value.int_value AS FLOAT64)), NULL)) AS refund_value
FROM `your-project.analytics_123456789.events_*`,
UNNEST(event_params) AS ep
WHERE _TABLE_SUFFIX BETWEEN FORMAT_DATE('%Y%m%d', start_date) AND FORMAT_DATE('%Y%m%d', end_date)
AND event_name = 'refund'
GROUP BY user_pseudo_id, event_timestamp, event_bundle_sequence_id
)
-- Chargebacks carry no flag on the refund event; they are issuer-initiated and are not sent as merchant refund events
-- Refunds issued, full and partial alike, one per refund_id; a missing value is a full refund; test/internal orders and voided authorisations (value sent as 0) excluded
SELECT
COUNT(DISTINCT refund_id) AS refunds_issued
FROM refunds
WHERE COALESCE(traffic_type, '') NOT IN ('internal', 'test')
AND (refund_value IS NULL OR refund_value <> 0);Adobe Experience Platform (AEP Query Service)
-- ==========================================
-- 2. ADOBE AEP QUERY SERVICE SQL
-- ==========================================
-- Chargebacks carry no flag on the refund event; they are issuer-initiated and are not sent as merchant refund events
-- Refunds issued in the period (last 90 days to yesterday), full and partial alike, one per refundID; a missing refundAmount is a full refund; test/internal orders and voided authorisations (refundAmount sent as 0) excluded
SELECT
COUNT(DISTINCT _tenantId.refund.refundID) AS refunds_issued
FROM aep_web_events_dataset
WHERE CAST(timestamp AS DATE) BETWEEN DATE_SUB(CURRENT_DATE, 90) AND DATE_SUB(CURRENT_DATE, 1)
AND eventType = 'refund'
AND COALESCE(_tenantId.trafficType, '') NOT IN ('internal', 'test')
AND (_tenantId.refund.refundAmount IS NULL OR _tenantId.refund.refundAmount <> 0);Source Data
Digital Analytics (GA4) + Commerce Platform Orders (Shopify / Salesforce Commerce Cloud / Adobe Commerce)
Dependencies
Prerequisite: List the dependencies required for this Metric
Events:
Dimensions:
Report Attributes
Refund Type Return Reason Return Method Payment Method Item Category Fulfillment Method Country
Recommended Reporting Views
Segment Eligibility
true
Governance
Derived KPIs
Governance
GitHub
catalog/metrics/refunds-issued.yml