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

{{ mobileViewTitle }}

{{ connected ? 'Live' : 'Offline' }} · {{ bids.length }}

PulseFlow Dashboard

{{ connected ? 'Connected' : 'Disconnected' }} • {{ bids.length }} events buffered
…
Requests
{{ stats.total }}
Matched
{{ stats.matched }}
{{ formatPercent(stats.matched, stats.total) }}
Won
{{ stats.won }}
{{ formatPercent(stats.won, stats.matched) }} of matched
Latency
~{{ stats.avgLatency }}ms
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:
{{ displayedBids.length }}
Rendering {{ displayedBids.length }} rows
{{ getStatusLabel(bid.status) }} {{ formatTimeAgo(bid.ts) }}
{{ bid.tagId || 'Unknown Sign' }}
{{ bid.publisher || 'Unknown Publisher' }}
{{ bid.campaign }} · {{ getCreativeId(bid) }}
Billed
Pending billing
${{ bid.price?.toFixed(2) || '0.00' }}
{{ bid.reasonDescription || bid.reasonCode || 'Loss' }}
${{ bid.bidPrice.toFixed(2) }} bid
Floor ${{ bid.bidfloor }}
{{ formatTime(bid.ts) }} {{ formatTimeAgo(bid.ts) }}
{{ getStatusLabel(bid.status) }}
{{ bid.tagId || 'Unknown Sign' }} {{ bid.size }} 📋 {{ bid.dealId }}
{{ 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 || '-' }}
Deal ID
{{ selectedBid.dealId || '-' }}
Creative ID
{{ getCreativeId(selectedBid) || '-' }}
Campaign & Placement
Campaign
{{ getBidCampaignObj(selectedBid)?.name || selectedBid.campaign || selectedBid.campaignId }}
Publisher
{{ selectedBid.publisher }}
Sign ID
{{ selectedBid.tagId }}
Creative Size
{{ selectedBid.size }}
Deal ID
{{ selectedBid.dealId }}
Bid CPM
${{ selectedBid.bidPrice.toFixed(4) }}
Floor Price
${{ selectedBid.bidfloor }}
Win Price
${{ selectedBid.price?.toFixed(4) }}
Timestamp
{{ new Date(selectedBid.ts).toLocaleString() }}
Live Campaign
{{ getBidCampaignObj(selectedBid).name || getBidCampaignObj(selectedBid).id }}
Active
Eligibility debug not available for this row (recorded before the live-feed fix, or no debug was captured). Open a new bid after deploy to see candidates and checks.
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.
Full OpenRTB Bid Request
{{ selectedBid.rawRequestText }}
Length: {{ selectedBid.rawRequestText.length.toLocaleString() }} chars
Creative Preview
{{ getPreviewAdmType(selectedBid) }} {{ getVastDuration(selectedBid) || (bidCreativeDuration ? bidCreativeDuration + 's' : '') }}
Loading creative…
VAST Video Ad
Duration: {{ getVastDuration(selectedBid) }}
{{ getCreativeType(selectedBid) }} Creative Content
{{ getCreativeContent(selectedBid) }}
Type: {{ getAdmType(selectedBid) }} Length: {{ getCreativeContent(selectedBid).length.toLocaleString() }} chars Duration: {{ getVastDuration(selectedBid) }}
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) }}

Settings

Stream status
Archive no-bids
Save no-bid events to PostgreSQL
Show no-match
Diagnostic RTDB events only
Appearance
Clear event buffer