Vue Logo

Sign in

to continue to PulseFlow Live Monitor

Can't access your account?

{{ loginEmail }}

Success!

Sign in failed

{{ loginError }}

Signing in...

Terms of use • Privacy & cookies

PulseFlow Dashboard

{{ connected ? 'Connected' : 'Disconnected' }} • {{ bids.length }} events buffered
Total Requests
{{ stats.total }}
Matched / Forwarded
{{ stats.matched }}
({{ formatPercent(stats.matched, stats.total) }})
Bids Won
{{ stats.won }}
({{ formatPercent(stats.won, stats.matched) }} of matched)
Avg Latency
~{{ stats.avgLatency }}ms

Last 24 hours

Requests by hour, win/loss rates, top signs, and loss reasons. Updated: {{ dashLastRefreshed }}

{{ dashError }}
Requests
{{ dashTotals.requests }}
Bid Rate
{{ dashTotals.bidRate }}%
Wins
{{ dashTotals.wins }} ({{ dashTotals.winRate }}%)
Losses
{{ dashTotals.losses }} ({{ dashTotals.lossRate }}%)
Billed
{{ dashBilling.billed }} ({{ dashBilling.billRate }}%)
Impressions
{{ dashBilling.impressions }}
Spend
${{ formatMoney(dashBilling.spend) }}
eCPM
${{ formatMoney(dashBilling.ecpm) }}
Unique Signs
{{ dashTotals.uniqueSigns }}
Unique Campaigns
{{ dashTotals.uniqueCampaigns }}
Active Campaigns
{{ dashPacing.activeCampaigns }}
Pacing Health
{{ dashPacing.overallPacingHealth }}%
Operational alerts
{{ a }}
Requests received by hour (last 24)
Truncated (too many rows)
Loading… Sign in to view metrics. No data (Firestorm bid logs may be disabled).
{{ h.short }}
Top signs (by requests)
No sign data.
{{ s.signName || s.signId }}
{{ s.signId }}
Wins: {{ s.wins }} • Losses: {{ s.losses }}
{{ s.requests }}
req • {{ s.winRate }}% win
Loss reasons (top)
No loss reasons captured.
{{ r.reason }}
{{ r.count }}
Top campaigns (by spend)
No campaign spend data.
{{ c.campaignId }}
Billed imps: {{ c.impressions }} • eCPM: ${{ formatMoney(c.ecpm) }}
${{ formatMoney(c.spend) }}
spend
Top publishers (by requests)
No publisher data.
{{ p.publisher }}
Bid rate: {{ p.bidRate }}% • Win rate: {{ p.winRate }}%
{{ p.requests }}
req

Campaigns & pacing

Active campaigns and their current pacing health.

{{ campaignsError }}
Active campaigns
{{ campaigns.length }}
Loading…
No active campaigns found.
Selected campaign
{{ selectedCampaignId }}
Select a campaign to view pacing.
Loading pacing…
{{ campaignInfoError }}
Daily Budget
${{ formatMoney(selectedCampaignInfo?.pacing?.dailyBudget) }}
Spent Today
${{ formatMoney(selectedCampaignInfo?.pacing?.spentToday) }}
Remaining
${{ formatMoney(selectedCampaignInfo?.pacing?.remainingBudget) }}
Pacing Health
{{ formatPercentFixed(selectedCampaignInfo?.pacing?.pacingHealth) }}%
Notes
Under-pacing: {{ !!selectedCampaignInfo?.pacing?.isUnderPacing }} • Over-pacing: {{ !!selectedCampaignInfo?.pacing?.isOverPacing }} • Last updated: {{ selectedCampaignInfo?.pacing?.lastUpdated || '—' }}
Engine plan (server)
Exact pacing targets/limits computed by PulseFlow right now.
{{ liveSummary.generatedAt }}
No live plan yet: {{ livePlan?.reason || 'pacing not initialized' }}.
Today
Active now: {{ !!livePlan?.schedule?.isActiveNow }}
Daily limit: ${{ formatMoney(livePlan?.budgets?.dailyBudgetLimit) }}
Allowed today: ${{ formatMoney(livePlan?.budgets?.allowedDailyLimit) }}
Remaining today: ${{ formatMoney(livePlan?.budgets?.remainingBudgetToday) }}
Health
Expected by now: ${{ formatMoney(livePlan?.health?.expectedSpendByNow) }}
Health today: {{ formatPercentFixed(livePlan?.health?.healthToday) }}%
Campaign health: {{ formatPercentFixed(livePlan?.health?.pacingHealth) }}%
10-minute pacing
Cap (now): ${{ formatMoney(livePlan?.plan?.maxBudgetPer10Minutes) }}
Bucket used: ${{ formatMoney(liveSummary?.derived?.distributed10MinuteSpent) }}
Bucket remaining: ${{ formatMoney(liveSummary?.derived?.tenMinuteRemaining) }}
Rate plan
Target hourly: ${{ formatMoney(livePlan?.plan?.targetHourlyBudget) }}
Max hourly: ${{ formatMoney(livePlan?.plan?.maxHourlyBudget) }}
Target/active hr: ${{ formatMoney(liveSummary?.derived?.targetPerActiveHour) }}
Per-sign pacing (engine)
{{ perSignMeta.returned }} / {{ perSignMeta.totalSigns }} signs (truncated to {{ perSignMeta.signLimit }})
Resolving sign asset names…
Per-sign pacing is enabled, but no per-sign budgets/signs were returned.
Asset Daily limit Spent today Remaining today Health 10m cap 10m used 10m rem
Totals ${{ formatMoney(perSignTotals.dailyBudgetLimit) }} ${{ formatMoney(perSignTotals.spentToday) }} ${{ formatMoney(perSignTotals.remainingBudgetToday) }} — — — —
{{ perSignResolved?.[s.signId]?.asset_name || perSignResolved?.[s.signId]?.displayName || '—' }}
OpenRTB: {{ s.signId }} {{ s.signTimeZoneId }}
${{ formatMoney(s?.budgets?.dailyBudgetLimit) }} ${{ formatMoney(s?.budgets?.spentToday) }} ${{ formatMoney(s?.budgets?.remainingBudgetToday) }} {{ formatPercentFixed(s?.health?.healthToday) }}% ${{ formatMoney(s?.plan?.effectiveMaxBudget) }} ${{ formatMoney(s?.buckets?.distributed10MinuteSpent) }} ${{ formatMoney(s?.buckets?.tenMinuteRemaining) }}
Pacing chart
Shows both: active-hours pacing + billing spend pacing (Admin-style).
{{ pacingTodayBadge.label }}
Active-hours pacing (engine)
0%
Health: {{ formatPercentFixed(pacingTodayHealth) }}%
200%
Spent today: ${{ formatMoney(selectedCampaignInfo?.pacing?.spentToday) }} • Daily budget: ${{ formatMoney(selectedCampaignInfo?.pacing?.dailyBudget) }} • Est. target by now: ${{ formatMoney(pacingTodayExpectedByNow) }}
Billed spend pace (lifetime)
Billed spend vs campaign time elapsed (from Firestore rollups).
{{ spendPaceBadge.label }}
Loading spend… Spend analytics loading in background…
0%
Pace: {{ formatPercentFixed(spendPacePct) }}%
200%
Spent to date: ${{ formatMoney(spendTotalToDate) }} • Expected by now: ${{ formatMoney(spendExpectedToDate) }} • Budget: ${{ formatMoney(campaignTotalBudget) }}
Billed spend by day
{{ dailySpendBars.length }} day(s)
Loading billed spend…
No daily spend docs yet.
{{ dailySpendBars[0]?.date || '' }}
target/day: ${{ formatMoney(dailySpendTarget) }}
{{ dailySpendBars[dailySpendBars.length - 1]?.date || '' }}
Today (active hours)
{{ hourlyToday.dateKey }}
Loading…
Loaded
Shows spend per hour (from billing) for today in campaign timezone.
No billing spend observed for today yet.
Active hours today: {{ hourlyActiveHoursLabel }} • Need: ${{ formatMoney(requiredPerRemainingActiveHour) }}/hr to hit EOD • Target (active hr): ${{ formatMoney(targetPerActiveHour) }}/hr • Remaining active hours: {{ remainingActiveHoursToday }}
{{ repaceStatus.label }} • Need is +{{ formatPercentFixed(repaceDeltaPct) }}% vs target, so hourly bars rise while re‑pacing. • Need is in line with target for on‑pace delivery.
00
active hours highlighted • hover for details
23
No pacing data available yet.
{{ line }}

All Billing Records

Complete billing history for all campaigns (active and inactive) · Showing: {{ billingFilters.startDate }} to {{ billingFilters.endDate }}

{{ billingError }}
Select date range and click "Load Data" to fetch billing records. Only records within the selected date range are included.
Campaigns ({{ filteredBillingCampaigns.length }} filtered)
{{ billingSummary.totalCampaigns || 0 }}
{{ billingSummary.activeCampaigns || 0 }} active, {{ billingSummary.inactiveCampaigns || 0 }} inactive
Total Amount
${{ formatMoney(billingSummary.totalAmount || 0) }}
Including markup
Profit
${{ formatMoney(billingSummary.profit || billingSummary.techFee || 0) }}
{{ formatPercent(billingSummary.profitMargin || billingSummary.techFeePercentage || 0, 100) }} margin
Base Spend
${{ formatMoney(billingSummary.spend || 0) }}
Excl. markup
Impressions
{{ billingSummary.impressions?.toLocaleString() || 0 }}
Avg eCPM
${{ formatMoney(billingSummary.averageCpm || 0) }}
Loading billing records...
No Data Loaded
Select a date range and click "Load Data" to view billing records
Campaign ID
Name
Client DSP Instance Seller IDs Sign IDs Status
Total Amount
Profit
Impressions
eCPM Records Date Range (Filtered)
{{ campaign.campaignId }} {{ campaign.campaignName || 'Unnamed' }} — {{ campaign.dspInstanceNames[0] }} +{{ campaign.dspInstanceNames.length - 1 }} — {{ campaign.sellerIds[0] }} +{{ campaign.sellerIds.length - 1 }} —
+{{ campaign.signIds.length - 1 }} more
—
{{ campaign.status }} ${{ formatMoney(campaign.totalAmount || campaign.spend || 0) }} ${{ formatMoney(campaign.techFee || 0) }} {{ (campaign.impressions || 0).toLocaleString() }} ${{ formatMoney(campaign.impressions > 0 ? (campaign.totalAmount / campaign.impressions) * 1000 : 0) }} {{ campaign.recordCount || 0 }} {{ campaign.firstBillingDate }} to {{ campaign.lastBillingDate }}
Date Spend Tech Fee Total Impressions Records
{{ record.date }} ${{ formatMoney(record.spend || 0) }} ${{ formatMoney(record.techFee || 0) }} ${{ formatMoney(record.totalAmount || 0) }} {{ (record.impressions || 0).toLocaleString() }} {{ record.recordCount || 0 }}
Date Campaign ID Spend Tech Fee Total Impressions
{{ record.date }} {{ record.campaignId }} ${{ formatMoney(record.spend || 0) }} ${{ formatMoney(record.techFee || 0) }} ${{ formatMoney(record.totalAmount || 0) }} {{ (record.impressions || 0).toLocaleString() }}
Showing first 500 of {{ billingIndividualRecords.length.toLocaleString() }} records

Client Details

Loading client details...
{{ clientModalError }}
Client Information
Client ID: {{ selectedClient.clientId }}
Name: {{ selectedClient.name || '—' }}
Domain: {{ selectedClient.domain || '—' }}
Seat ID: {{ selectedClient.seatId || '—' }}
Notes: {{ selectedClient.notes }}
User Information
User ID: {{ selectedClient.userId }}
Name: {{ selectedClientUser.name || '—' }}
Email: {{ selectedClientUser.email || '—' }}
Phone: {{ selectedClientUser.phoneNumber }}
Business Account: {{ selectedClientUser.isBusinessAccount ? 'Yes' : 'No' }}
Price Preference: {{ selectedClientUser.pricePreference }}

Sign Details

Loading sign details...
{{ signModalError }}
Sign Information
Asset Name:
{{ selectedSign.asset_name || '—' }}
Sign ID:
{{ selectedSign.id || selectedSign.adunit_id || '—' }}
Publisher:
{{ selectedSign.publisher || '—' }}
Seller ID:
{{ selectedSign.seller_id || selectedSign.sellerId || '—' }}
Location:
{{ selectedSign.latitude && selectedSign.longitude ? `${selectedSign.latitude}, ${selectedSign.longitude}` : '—' }}
Status:
{{ selectedSign.status || '—' }}
City/State:
{{ selectedSign.city || '' }}{{ selectedSign.city && selectedSign.state ? ', ' : '' }}{{ selectedSign.state || '' }}
Network:
{{ selectedSign.network }}
Media Type:
{{ selectedSign.media_type }}
OpenRTB UUID:
{{ selectedSign.openRTBUUID }}
Location Details
Venue:
{{ selectedSign.venue_name }}
Address:
{{ selectedSign.address }}

Search by Inventory

Select a date range to find available signs and publishers, then filter billing data by your selection.

Step 1: Select Date Range
{{ inventorySearch.error }}
Search Results
Total Records
{{ inventorySearch.results.totalRecords.toLocaleString() }}
Unique Signs
{{ inventorySearch.results.signs.length.toLocaleString() }}
Unique Publishers
{{ inventorySearch.results.sellers.length.toLocaleString() }}
Costs shown are base spend only (excluding tech fees)
Step 2: Search by Sign
No signs match your search
OR
Step 2: Search by Publisher
No publishers match your search
Select dates to search for available signs and publishers
This will help you filter billing data by specific inventory
Time
Status
Sign / Publisher
Details
Show:
Rendering {{ displayedBids.length }} rows
{{ formatTime(bid.ts) }} {{ formatTimeAgo(bid.ts) }}
{{ getStatusLabel(bid.status) }}
{{ bid.tagId || 'Unknown Sign' }} {{ bid.size }}
{{ bid.publisher || 'Unknown Publisher' }} • Campaign: {{ bid.campaign }} • Creative: {{ getCreativeId(bid) }}
BILLED
PENDING
WIN: ${{ bid.price?.toFixed(2) || '0.00' }}
LOSS: {{ bid.reasonDescription || bid.reasonCode || 'No reason' }}
BID: ${{ bid.bidPrice.toFixed(2) }}
Floor: ${{ bid.bidfloor }}

Waiting for incoming bids...

Bid Details

Status
{{ getStatusLabel(selectedBid.status) }}
Reason/Error
{{ selectedBid.reasonDescription || selectedBid.lossDetail || selectedBid.reason || selectedBid.error || '-' }}
Latency
~{{ Math.floor(Math.random() * 50 + 20) }}ms
Request ID
{{ selectedBid.id }}
Sign ID
{{ selectedBid.tagId || '-' }}
Creative ID
{{ getCreativeId(selectedBid) || '-' }}
Candidate Campaigns
{{ cand }}
Eligibility Checks
{{ (selectedBid.rejectionDetails && selectedBid.rejectionDetails.length) ? selectedBid.rejectionDetails.length : (selectedBid.rejectionSummary ? Object.keys(selectedBid.rejectionSummary).length : 0) }} checked
checked {{ rej.campaignName }}
{{ rej.campaignId }}
reason - {{ rej.reason }}
checked {{ campaignId }}
reason - {{ reason }}
💎 Bid Cost Calculation
Impressions/Multiplier
{{ selectedBid.impressions }}
CPM Bid
${{ selectedBid.bidPrice.toFixed(4) }}
Calculated Cost
${{ selectedBid.actualCost.toFixed(6) }}
Pacing Cost (Conservative)
${{ selectedBid.pacingCost.toFixed(6) }}
{{ selectedBid.pacingCostSource }}
Pacing Cost Details
{{ JSON.stringify(selectedBid.pacing.pacingCostDetails, null, 2) }}
This shows the exact cost calculation used for pacing decisions. With qty.multiplier, costs are calculated before the bid wins.
No Cost Data Available

Cost calculations are not available for this rejection type.

Rejection Reason:
{{ selectedBid.reason || selectedBid.reasonDescription }}
bidPrice: {{ selectedBid.bidPrice ?? 'null' }}
actualCost: {{ selectedBid.actualCost ?? 'null' }}
pacingCost: {{ selectedBid.pacingCost ?? 'null' }}
impressions: {{ selectedBid.impressions ?? 'null' }}

Why no cost data?

• Early rejections (no campaign, invalid price) happen before cost calculation

• Pacing rejections include full cost details

• Older events from before this feature was added

Full OpenRTB Bid Request
{{ selectedBid.rawRequestText }}
Length: {{ selectedBid.rawRequestText.length.toLocaleString() }} chars
{{ getCreativeType(selectedBid) }} Creative Content
{{ getCreativeContent(selectedBid) }}
Type: {{ getAdmType(selectedBid) }} Length: {{ getCreativeContent(selectedBid).length.toLocaleString() }} chars Duration: {{ getVastDuration(selectedBid) }}
Creative Content Not Captured

The VAST/HTML creative content was stripped to save space.

To enable full creative logging:

fly secrets set LOG_BID_ADM_FULL=true

See CREATIVE_DEBUGGING.md for details

Full OpenRTB Bid Response
{{ JSON.stringify(selectedBid.response, null, 2) }}
Seatbids: {{ selectedBid.response.seatbid?.length || 0 }} NBR Code: {{ selectedBid.response.nbr }} Length: {{ JSON.stringify(selectedBid.response).length.toLocaleString() }} chars
Full Win Notification
{{ JSON.stringify(selectedBid.winNotification, null, 2) }}
Price: ${{ selectedBid.winNotification.price.toFixed(2) }} Impressions: {{ selectedBid.winNotification.impressions }} Time: {{ new Date(selectedBid.winNotification.timestamp).toLocaleString() }}
Full Loss Notification
{{ JSON.stringify(selectedBid.lossNotification, null, 2) }}
Reason Code: {{ selectedBid.lossNotification.reason }} Description: {{ selectedBid.lossNotification.reasonDescription }} Time: {{ new Date(selectedBid.lossNotification.timestamp).toLocaleString() }}
Billing Notification
{{ JSON.stringify(selectedBid.billingRaw || { price: selectedBid.billingPrice, timestamp: selectedBid.billingTimestamp }, null, 2) }}