If you run paid acquisition for a SaaS, freemium, or trial-based business in 2026, the Stripe Dashboard tells you what revenue you made. What it does not tell you is which signups from your $50,000 of Meta Ads spend last month actually converted from trial to paid, how many got stuck in dunning at month two, and which acquisition channels recover failed payments versus which ones churn silently. Most SaaS marketers operate on signup counts because the trial-to-paid funnel and the failed payment funnel are invisible inside the default Stripe reporting.
This guide covers three methods to pull Stripe data into Looker Studio in 2026, the Stripe-specific gotchas at each layer, and the two SaaS marketing dashboards that change how acquisition is measured: the trial conversion funnel by acquisition channel and dunning recovery by acquisition channel. Neither is a default Stripe Dashboard view, both require joining Stripe data to your marketing source attribution, and both decide whether your paid acquisition is genuinely profitable or just looks that way for thirty days.
For the related layer of marketing reporting around this, see our marketing dashboard KPIs playbook, our existing Stripe to Google Sheets guide for the spreadsheet path, and our LinkedIn Ads to Google Sheets guide for the B2B paid acquisition source most SaaS companies care about. This post focuses on Looker Studio specifically and on the subscription-funnel angle. A quick note on naming: Google renamed Looker Studio back to Data Studio in early 2026, but in search behavior and in everyday use most marketers still call it Looker Studio, so that is the name we use throughout. The product, the connector ecosystem, and the pricing are unchanged.
Where the subscription funnel lives in Stripe
Before picking a method, you need to know what Stripe exposes and where the relevant fields hide. The trial-to-paid funnel and the dunning funnel both span several Stripe objects.
- Customer. The top-level record. Carries the
createddate (your signup-equivalent timestamp),metadata(where most teams store the acquisition channel or UTM source), and links to subscriptions, charges, invoices, and payment methods. - Subscription. The subscription record. Carries
status(trialing, active, past_due, canceled, unpaid, incomplete),trial_startandtrial_enddates,start_date,canceled_at, and the structuredcancellation_detailsobject withreasonandfeedbackfields populated by your churn surveys. - Invoice. The billing artifact. Carries
attempt_count(how many times Stripe retried a failed payment),next_payment_attempt, andstatus(draft, open, paid, void, uncollectible). The dunning funnel lives inside invoice attempt counts and status transitions. - PaymentIntent. The payment attempt. Carries
status(succeeded, requires_payment_method, canceled) andlast_payment_error.code, which tells you whether the failure was a card declined, insufficient funds, expired card, or fraud block. Recovery rate varies dramatically by failure reason. - Charge. The successful payment. Where the actual revenue is recorded with currency, refund history, and dispute information.
For the marketing acquisition story, the critical piece is the metadata field on Customer (or Subscription) where your signup form stamps the acquisition channel. If your signup form does not write to metadata, you are flying blind. Stripe will not infer marketing channel from anywhere else.
Method 1: Manual CSV export from the Stripe Dashboard
For one-off audits, monthly board snapshots, or before you have a real reporting setup. Fast, free, brittle the moment you need any segmentation.
Setup: in Stripe Dashboard, navigate to Customers, Subscriptions, or Invoices. Click Export. Choose CSV. Choose date range. Download. Open in Sheets. Manually join across exports if you need a complete funnel view.
Stripe-specific gotchas at this layer:
- Each export is a single object type. A trial-to-paid funnel needs customers, subscriptions, AND invoices joined. That is three exports per snapshot, then VLOOKUP gymnastics in Sheets to stitch them together.
- Metadata is not included in default exports. Your custom channel field stored in
metadatatypically requires either the Sigma SQL layer or the API. The default Stripe CSV export gives you canonical fields only. - No incremental refresh. Every export is a fresh download from start. Building a weekly cadence means accumulating snapshots forward yourself in Sheets.
- Cancellation reasons require the survey to be live. The
cancellation_details.reasonfield only populates when you have configured the Stripe Billing Portal cancellation survey. Most teams configure it once, then forget; check that survey responses are being captured before you build a churn-by-reason dashboard.
When this method fits: board snapshot, quarterly review, audit before you invest in real tooling.
When it does not: any dashboard that refreshes more than monthly, anything joining Stripe to your paid media spend, anything segmenting by acquisition channel.
Method 2: Apps Script with the Stripe API
The DIY path for a SaaS marketing or RevOps team comfortable with a bit of code. Setup is 45-90 minutes the first time, then 20-30 minutes per additional report. The result lands in Sheets, which then connects to Looker Studio as the data source.
Step 1. Generate a Stripe restricted API key. In Stripe Dashboard: Developers, then API keys, then Create restricted key. Scope it to read access on Customers, Subscriptions, Invoices, Charges, and PaymentIntents only. Never use a full secret key for read workflows; restricted keys are scoped and revocable.
Step 2. In your Google Sheet, open Extensions, then Apps Script and paste a script along these lines:
function exportStripeSubscriptionsWithChannel() {
const STRIPE_KEY = 'rk_live_YOUR_RESTRICTED_KEY';
const baseUrl = 'https://api.stripe.com/v1/subscriptions';
const headers = {
'Authorization': 'Bearer ' + STRIPE_KEY,
'Stripe-Version': '2024-09-30.acacia'
};
const sheet = SpreadsheetApp.getActiveSheet();
sheet.clear();
sheet.appendRow(['Subscription ID', 'Customer ID', 'Status', 'Trial Start', 'Trial End', 'Start Date', 'Canceled At', 'Cancellation Reason', 'Acquisition Channel']);
let url = baseUrl + '?limit=100&expand[]=data.customer';
while (url) {
const response = UrlFetchApp.fetch(url, { headers: headers, muteHttpExceptions: true });
const data = JSON.parse(response.getContentText());
(data.data || []).forEach(sub => {
const channel = (sub.customer && sub.customer.metadata) ? sub.customer.metadata.acquisition_channel : '';
const reason = (sub.cancellation_details) ? sub.cancellation_details.reason : '';
sheet.appendRow([sub.id, sub.customer.id, sub.status, sub.trial_start, sub.trial_end, sub.start_date, sub.canceled_at, reason, channel]);
});
url = data.has_more ? baseUrl + '?limit=100&starting_after=' + data.data[data.data.length - 1].id + '&expand[]=data.customer' : null;
}
}
The Stripe API reference documents every endpoint, expand parameter, and pagination pattern. The API versioning docs explain how the Stripe-Version header works. For dunning behavior specifics, see the Stripe Smart Retries documentation.
Step 3. Connect the Sheet to Looker Studio. In Looker Studio, Create, then Data source, then Google Sheets connector, point at your Stripe sheet, click Connect. Refresh schedule is configurable from the Looker Studio side; the Apps Script trigger handles the underlying refresh from Stripe.
Step 4. Schedule the Apps Script. Apps Script, Triggers, Add Trigger, run your function daily before the team check-in.
Stripe-specific gotchas at the API layer:
- API versioning matters more than you think. The
Stripe-Versionheader pins which API version you call. Pin a version (a 2025 or early 2026 dated revision is the current standard) and stick to it. When Stripe deprecates one, they give you a long migration window, but they do not run forever. - Rate limits exist but are generous. Stripe documents roughly 100 read operations per second in live mode and 25 per second in test mode. You will not hit them for typical reporting workloads. Build retry-on-429 anyway for safety; rare bursts happen.
- Pagination is cursor-based with
starting_after. Stripe does not page by page number; you pass the last object ID from the previous page. Thehas_morefield signals the end. Skip pagination logic and you only get the first 100 records. - Use
expandto inline related objects. By default, the customer field on a subscription is just a customer ID. To get the metadata, passexpand[]=data.customer. Each expand level adds latency; do not expand more than two levels deep. - Restricted keys are scoped and revocable. If your script gets compromised, you revoke the restricted key in the Dashboard and nothing else breaks. Never use the unrestricted secret key (
sk_live_with full access) in spreadsheets, repositories, or unmanaged endpoints. - Test mode versus live mode are separate. The
rk_test_prefix queries test data;rk_live_queries production. Confusing them is the most common pre-launch mistake. The Stripe Dashboard top-right has a toggle; the API key prefix should match the mode you intend. - Apps Script execution limit. Workspace Free: 6 minutes per execution. Workspace paid: 30 minutes. Pulling a year of subscriptions plus customer expansion plus invoices can blow past 6 minutes. Solution: process by month chunks, or move the workflow to Cloud Functions if you need longer runs.
Method 3: Scheduled no-code connector
The path for SaaS marketing teams that want Stripe data in Looker Studio on a schedule with no code, no API maintenance, and the acquisition channel field already aligned. Setup under 10 minutes.
Dataslayer connects Stripe to Looker Studio via the Stripe restricted API key flow. The connector queries the same Stripe API the manual script does, but exposes subscription status, cancellation reasons, subscription metadata, trial dates, and invoice status as native queryable dimensions in your Looker Studio data source. You point Looker Studio at the Dataslayer connector, pick the fields, and the dashboard refreshes on the schedule you set.
Why a connector matters specifically for SaaS marketing reporting:
- Subscription funnel states as native fields. Status, trial_start, trial_end, canceled_at, and cancellation_reason ship as dimensions you can pivot directly. No JSON parsing, no expand path syntax.
- Subscription metadata exposed as fields. If you stamp the acquisition channel into
subscription.metadataat signup (in addition tocustomer.metadata), the connector exposes it as a native dimension you can pivot directly. That is the field that lets you segment trial conversion by channel without JSON extraction work; native customer-level metadata extraction is on the connector roadmap. - Joined to paid media in one workbook. Once Stripe and Meta Ads or LinkedIn Ads data both feed Looker Studio via the same connector layer, blended CAC by channel is a calculated field away.
- Past invoice retrieval is opt-in. The connector exposes a setting to pull historical invoices (with the API cost that implies). For ongoing dashboards you do not need this; for backfilling a year of dunning data once, you turn it on.
Costs: a free tier covers a single connector and user; paid tiers scale up to multiple Stripe accounts in one workspace. Current pricing here.
The Stripe gotcha that NO method fixes: if your signup form does not write the acquisition channel to metadata at customer creation, no dashboard can recover the data. Fix the signup form first. Stamp utm_source, utm_medium, utm_campaign, and landing_page as separate fields on customer.metadata, and copy the same values into subscription.metadata when the subscription is created. Most reporting connectors surface subscription metadata natively as queryable dimensions, while customer metadata typically sits inside the customer JSON object and requires extraction work. Do this before you build any of the dashboards in this post.
The 2 SaaS marketing dashboards worth building
Once Stripe data flows into Looker Studio with the acquisition channel field aligned, these two reports change how SaaS marketing teams measure paid acquisition. Neither is a default Stripe Dashboard view, both require the metadata stamping above, and both answer questions the signup count alone hides.
Dashboard 1: Trial conversion funnel by acquisition channel
The question: of the 1,200 trial signups Meta Ads brought in last month, how many actually converted to paid by day 14, and how does that conversion rate compare to LinkedIn Ads or organic search? What is the true CAC after factoring trial-to-paid conversion, not just signup count?
Funnel stages to extract from Stripe:
- Customers created (day zero, by acquisition channel)
- Subscriptions with
status= trialing (active trial) - Subscriptions where
trial_endhas passed andstatustransitioned to active (trial-to-paid conversion) - Subscriptions where
trial_endpassed andstatus= canceled (trial drop-off)
Columns to pull from Meta Ads, LinkedIn Ads, or Google Ads:
- Campaign ID, daily spend, conversions reported by the platform
- UTM source/medium on the landing page that maps to Stripe's
metadata.acquisition_channel
Calculations in Looker Studio (or in the Sheet feeding it):
- Trial conversion rate by channel: COUNT(status = active AND trial_end < today) ÷ COUNT(trial_start <= today - 14)
- True CAC by channel: SUM(channel_spend) ÷ COUNT(active paid subscriptions from that channel)
- CAC payback period: CAC ÷ (average MRR per customer for that channel)
Looker Studio layout:
- Time-series chart: weekly trial signups, trial conversions, and conversion rate per channel
- Bar chart: True CAC by channel (sorted ascending)
- Scorecard: blended CAC payback period in months
- Filter controls: date range, channel multi-select
What this dashboard surfaces that signup counts hide:
- Channels with high signup volume but poor trial-to-paid conversion (your Meta Ads creative that converts to free trial signup at a great cost but where almost nobody pays)
- Channels with low signup volume but excellent trial-to-paid conversion (the high-intent referral or comparison-site source that costs nothing and converts at 60%)
- The actual CAC after trial drop-off, not the inflated marketing-platform CAC measured at signup
Dashboard 2: Dunning recovery by acquisition channel
The question: when a paid customer's card fails, do customers acquired through Meta Ads recover their payment at the same rate as those from LinkedIn or organic? Are you losing recoverable revenue silently to certain channels?
Data to extract from Stripe:
- Invoice
id,customer,status,due_date,amount_due,created - Invoice transitions: status remaining
openpastdue_datemeans Stripe Smart Retries dunning is iterating on the customer's payment method - PaymentIntent
last_payment_error.codeattached to the invoice (card_declined, insufficient_funds, expired_card) - Final invoice status:
paid(recovered),uncollectible(failed dunning), orvoid(canceled before recovery) - Subscription
metadata.acquisition_channelon the parent subscription (write this at subscription creation for native dimension access)
Calculations in Looker Studio:
- Dunning recovery rate by channel: COUNT(invoices that transitioned from
openpastdue_dateto final statuspaid) ÷ COUNT(invoices that stayedopenpastdue_dateat least once) - Lost revenue by channel: SUM(amount_due) where final status = uncollectible, grouped by channel
- Failure reason breakdown: COUNT by
last_payment_error.code
Looker Studio layout:
- Heat map: rows = acquisition channel, columns = failure reason, cells = recovery rate
- Bar chart: total uncollectible revenue lost by channel (last 90 days)
- Scorecard: blended dunning recovery rate, with trend versus prior period
What this dashboard surfaces that the default Stripe reports do not:
- Channels where customers churn through silent payment failure (your Meta retargeting audience that signs up enthusiastically, never updates a card, and quietly cancels at first failed renewal)
- Failure reason concentration by channel (channels skewing toward expired cards versus insufficient funds tell different stories about audience quality)
- The recoverable revenue you are leaving on the table because your dunning emails are not tuned per channel
Comparing the three methods
The decision usually comes down to whether your acquisition channel is already stamped into customer.metadata and how often the dashboard refreshes. Stamped and weekly refresh: manual works. Stamped and daily refresh: Apps Script. Stamped, multi-channel join, and you want time back: scheduled connector.
Stripe quirks worth knowing
Five behaviors that affect every method and every dashboard built on top of Stripe subscription data:
- Status transitions are not always linear. A subscription can go from
trialingtoactivetopast_dueback toactive(recovered dunning), then tocanceled. To measure trial-to-paid conversion correctly, query the status at the momenttrial_endpassed, not the current status. Use a snapshot or the events log; current state alone hides the funnel. - Proration changes the MRR math. Mid-cycle plan changes trigger prorated invoices. If you compute MRR by summing all invoices in a month, mid-cycle upgrades or downgrades double-count or double-discount. Use
subscription.plan.amountat the period boundary instead of invoice sums. - Trial extensions silently move
trial_end. Customer support team granting a one-week trial extension shifts thetrial_enddate on the subscription object. Your "did this customer convert by day 14" query needs to anchor ontrial_startplus a fixed offset, not on whatevertrial_endis right now. - Test mode subscriptions look identical to live. If your reporting accidentally points at the test API key, the data looks plausible and your dashboard quietly reports test subscriptions. Audit which key prefix your connector uses on first setup; many post-mortems end here.
- Customer.metadata is unstructured. Stripe does not validate the keys or values you write into
metadata. If your signup form writessourcein some flows andacquisition_channelin others, your dashboard sees them as different fields. Standardize the metadata key names at the signup form layer first.
Common errors and how to read them
401 unauthorized: the restricted API key is invalid, revoked, or missing the Bearer prefix in the Authorization header. Also fires if you used a rk_test_ key against live data or vice versa.
403 forbidden: the restricted key was created without the required scope on the object you are requesting. Edit the key in Dashboard, expand scopes (read access on the relevant object types), save, retry.
429 too many requests: rate limit hit. Stripe returns a 429 with no Retry-After header by default; implement exponential backoff starting at 1 second and doubling up to 32 seconds. Rare for read workflows; common if you accidentally loop without pagination.
400 bad request with parameter error: usually an unknown parameter or a malformed expand[] path. Stripe's error message tells you which parameter; consult the API reference for the correct shape.
Empty data array on subscriptions: common cause is filtering by a status that does not exist (typos like active_status instead of active), or pulling from test mode where you have no real data. Verify the key prefix and the status spelling.
FAQ
Can Looker Studio connect to Stripe natively in 2026?
Looker Studio has no first-party native Stripe connector. The Looker Studio Connector Gallery contains Partner Connectors built by third parties (typically priced at $5-25 per user per month) that bridge Stripe to Looker Studio. The alternative is to land Stripe data into Google Sheets or BigQuery first, then point Looker Studio at that data source.
How do I track the acquisition channel for a Stripe customer?
Write utm_source, utm_medium, utm_campaign, and a normalized acquisition_channel field into customer.metadata at the moment of customer creation, and copy the same values into subscription.metadata when the subscription is created. Stripe preserves both forever. Most reporting connectors surface subscription metadata as native queryable dimensions, while customer metadata typically sits inside the customer JSON object. Writing to both gives you native dimension access in the dashboard without JSON extraction. This is the single most important fix for SaaS marketing attribution.
What is the difference between subscription status and invoice status?
Subscription status describes the recurring billing relationship (trialing, active, past_due, canceled, unpaid, incomplete). Invoice status describes a single billing event within that relationship (draft, open, paid, void, uncollectible). A subscription can be active while its current invoice is open (unpaid but not yet failed); a subscription becomes past_due only after dunning attempts.
How can I join Stripe data with Meta Ads spend in Looker Studio?
Bring both into the same data source layer (Looker Studio with a partner connector, or Google Sheets/BigQuery with a connector landing both). Then create a calculated field in Looker Studio that joins on the channel dimension (typically the normalized acquisition_channel stamped in Stripe metadata, matched against utm_source in Meta Ads). For small datasets, a blend in Looker Studio works; for larger volumes, pre-aggregate in the data source layer.
How do I track trial-to-paid conversion in Stripe?
For each subscription created in a given month, snapshot the status at the moment trial_end passes. A subscription with status active at that point converted; one with canceled or incomplete did not. The Stripe Events log preserves these transitions; the current state of the subscription object does not. Most teams query events or maintain a daily snapshot of subscription state.
Why is my dunning recovery rate lower than Stripe's published benchmark?
Stripe publishes blended recovery benchmarks across all merchants. Your rate varies dramatically by audience quality (which is what acquisition channel reveals), card mix (corporate cards recover at higher rates than personal), geography (US/EU recover differently), and whether you have Smart Retries enabled in Billing settings. Segmenting recovery by channel reveals where your audience quality is leaking.
Conclusion
The three methods to pull Stripe into Looker Studio in 2026 sit on a spectrum: manual CSV for one-off audits, Apps Script for free automation if your team can maintain code and the metadata fields, scheduled connector for hands-off SaaS marketing dashboards across multiple paid channels. The right method depends on whether your signup form is already stamping acquisition channel into customer.metadata and how often the funnel needs to refresh.
But the methods are means, not the end. The two dashboards (trial conversion funnel by channel and dunning recovery by channel) are the work that changes how SaaS marketers measure paid acquisition. Both require the metadata stamping to be in place at the signup form, both require Stripe data joined to your paid media spend, and both answer the question that signup counts alone never could in 2026: which channels actually pay back, and on what timeline.
Fix the metadata stamping. Pull the Stripe data into Looker Studio. Build the two dashboards. Start a free Dataslayer trial if you want to skip the API maintenance and the metadata extraction work, and get straight to the dashboards.


.avif)




