Tag: automation

  • How to Build a Contact Center Performance Dashboard in Google Sheets

    Google Sheets can replace most of what contact center analytics platforms charge thousands of dollars for — if it’s set up correctly. Here’s how to build a live performance dashboard that surfaces list health, contact rate trends, and swap candidates without expensive software or a data team.

    ## What the Manual Alternative Looks Like

    Most contact centers running Telesero, Vicidial, or similar dialers track performance in spreadsheets already — but manually. The morning pull takes significant time: open the dialer reports, copy the numbers, paste them into the sheet, update the color coding, figure out which lists are underperforming, decide what to swap.

    By the time that’s done, the data is already hours old and the decisions being made are based on what happened yesterday, not what’s happening now.

    A properly structured Sheets dashboard with automated data ingestion eliminates the manual pull and gives the floor real visibility into list health across every active campaign — updated automatically on a schedule.

    ## What the Dashboard Tracks

    The metrics that matter for daily list management, structured into views that surface decisions rather than just data:

    **Health grid.** Every active list, color-coded by current performance state. At a glance: which lists are healthy, which are degrading, which need attention before the next session. The color isn’t manual — it’s calculated from the data and updates automatically when new records come in.

    **Trend panel.** Contact rate and conversion rate over a rolling window, per list. The decay curve tells you when a list is exhausting faster than usual, which is often a lead quality signal rather than a dialing strategy problem. A list that was converting well last week and is declining this week deserves different treatment than one that’s been flat for a month.

    **Swap candidates panel.** Lists ranked by swap priority — organized by performance state, time since last swap, and current metrics — so the decision of what to rotate next is structured rather than intuitive. The panel separates lists by priority tier and preserves the operator’s manual queue order while surfacing data-driven alternatives.

    ## The Architecture

    **Two data sources, one workbook.** A summary sheet holds aggregated metrics per list. A daily records sheet holds per-session performance data. Both connect to the same Google Sheets workbook, and the dashboard views are built on top of them.

    **Automated ingestion.** A scheduled script — running on a consistent cadence before the floor opens — pulls performance data from your dialer system, writes it to the appropriate sheet, and updates the timestamp. When the ops manager opens the dashboard in the morning, the data is already there. The morning pull is gone.

    **Calculated health states.** Rather than manual color coding, health states are calculated from the data. A list’s state (healthy, degrading, exhausted, recovering) is derived from its recent contact rate, conversion rate, time since last active session, and comparison against its own historical baseline — not against a fixed threshold applied to every list equally.

    **Swap scoring.** Each list gets a swap score that combines its current performance metrics, time in the active rotation, and recency of last swap. The score determines the ranked order in the swap candidates panel.

    ## The Complication: The Spreadsheet Isn’t the Automation

    The most common failure mode for teams that “automate” in Google Sheets is building sophisticated formulas and thinking that’s enough.

    It isn’t.

    Formulas calculate from data that’s already in the sheet. If the data gets there manually — someone opens the file and pastes in yesterday’s numbers — you haven’t automated anything. You’ve automated the calculation but not the collection. The bottleneck moved from “calculate” to “paste.”

    The automation that actually eliminates the morning pull is a scheduled script that writes data to the sheet before anyone opens it. Python with the Google Sheets API, or Google Apps Script on a time-based trigger, both work. The key requirement is that the sheet is populated before the floor opens — not refreshed when someone opens it.

    **The second complication is scale.** Google Sheets handles dozens of lists and hundreds of records well. As the list count grows and the history accumulates, formula complexity increases, multi-user edit conflicts emerge, and query times slow down. At a certain scale, the Sheets layer stops being the right tool for the data storage problem — it remains useful as a presentation layer, but the data should live somewhere faster underneath it.

    Knowing when you’ve hit that ceiling is useful information. A dashboard that performs well at your current scale and starts showing signs of strain as you grow is telling you something about where the next investment should go.

    ## Frequently Asked Questions

    **Does this work if our dialer doesn’t have a direct API?**
    The data ingestion approach depends on what your dialer exposes. Most systems (Telesero, Vicidial, Convoso, Five9) have either a direct API or a report export that can be automated. If direct API access isn’t available, scheduled report exports that get parsed and loaded work as an alternative, though with more fragility.

    **Can multiple people use the dashboard simultaneously?**
    Yes — the dashboard is read-only for most users. The automated script that writes data should be the only process making edits to the data sheets. Read-only access across a team works fine in Sheets at any scale.

    **How do we handle lists that are temporarily deactivated?**
    Deactivated lists should remain in the data set with their deactivation timestamp noted, not be removed. A list that gets deactivated and subsequently converts — someone who was called while active books an appointment after being removed from rotation — should surface in the swap candidates panel at elevated priority. The dashboard logic needs to track deactivated status explicitly to handle this correctly.

    **What’s the maintenance overhead?**
    Once the ingestion script and dashboard formulas are set up, maintenance is low — primarily keeping API credentials current and updating the list of active campaigns as your operation changes. A well-built implementation handles new lists automatically when they appear in the data source.

    ## If You’d Rather Have This Built

    I build performance dashboards for contact centers — Sheets-based for operations at current scale, with an eye toward what the architecture looks like when the operation grows. If you want the ingestion script, the health grid, and the swap candidates panel set up correctly — start here: rfditservices.com/intake.html

    The first conversation is free.

  • I Processed 671,000 Records in 6 Minutes and 32 Seconds

    The number that mattered wasn’t 671,000. It was 6:32.

    But before I got there, I had to survive a BOM file.

    What a BOM File Does to Your Morning

    A BOM — Byte Order Mark — is a hidden character. Three invisible bytes at the start of a UTF-8 encoded file, placed there by certain export tools as a signature. Completely benign in most contexts. Catastrophic if you’re parsing column headers programmatically and nobody told you it was there.

    The file came in as a standard monthly lead drop from a third-party vendor. CSV, normal structure, expected columns. I loaded it, ran my process, and watched it fail in a way that made no sense. The column I was looking for was right there in the header row. My code couldn’t find it.

    I opened the file in a hex editor. The first column name didn’t start with the letter I was looking at. It started with EF BB BF followed by the letter. Three bytes of invisible garbage prepended to the header, making Name into something my string comparison had never seen before and would never match.

    That was lesson one: files lie. Specifically, files produced by systems you don’t control lie in ways you won’t anticipate until they do it to you. The fix was one line. The lesson was architectural.

    Tool One: The Fuzzy Scrubber

    The lead data problem predates the BOM file. It starts with a simpler, more persistent irritant: duplicate companies.

    When you’re working with raw lead data at scale — scraped data, third-party drops, list purchases — you consistently encounter the same fundamental problem. A regional franchise has fifty locations. A corporate chain has a hundred. A national company has branch offices in every market you’re targeting. Each one appears as a separate row with a slightly different name. Smith Plumbing, Smith Plumbing LLC, Smith Plumbing of South Florida, Smith Plumbing — Boca Raton.

    You don’t want fifty versions of the same company. You want one, or none.

    The first tool I built was a fuzzy scrubber. Not exact match deduplication — exact match is easy and catches almost nothing. Fuzzy matching: similar names, above a threshold, clustered and collapsed. The goal was to identify companies that were likely regional, corporate, or franchise operations and remove them from the working set before they reached the dialer.

    The first threshold caught seven clusters. Too aggressive — legitimate distinct companies were getting collapsed. I tuned it. Three clusters. Better. Still not perfect, but better is the goal in data work. Perfect is a fiction that costs you the pipeline.

    The scrubber became step one of what would eventually be a twelve-step process. I didn’t know that yet.

    The Encoding Problem

    Every data engineer eventually learns that text encoding is not a solved problem.

    It’s solved in theory. UTF-8 is the standard. Everyone agreed. The agreement doesn’t survive contact with files produced by legacy systems, Windows-default exports, Excel users who have never thought about encoding in their lives, or third-party vendors whose ETL tools were written in 2003.

    The lead data came from multiple sources. Each source had its own encoding habits. Most of the time UTF-8 worked. Sometimes it didn’t, and the failure mode wasn’t a clean error — it was silent corruption. Characters mangled into question marks or replacement symbols. Phone numbers with invisible characters that made them unparseable. Company names with encoding artifacts that defeated fuzzy matching and left junk in the dataset.

    The encoding handler became step two. Detect the encoding before you process. Normalize to UTF-8 explicitly. Validate that the result is clean. Only then proceed.

    The BOM problem was a subcase of this. A BOM-aware reader handles it automatically. I had not been using a BOM-aware reader. I was, after the BOM incident.

    Common Columns and the First Real Pattern

    By the time I had a fuzzy scrubber and an encoding handler, I was starting to see a pattern in what the data needed across different downstream destinations.

    We run multiple dialer systems. Each dialer has its own expected column format. The CRM backend has its own schema. A lead that’s processed correctly for one system is formatted wrong for another. If you’re loading data manually into each system, this is an annoyance — you reformat before each import. If you’re trying to automate the flow, it’s a structural blocker.

    I started mapping what each system actually needed. What columns. What names. What formats. What was optional, what was required, what would cause a silent failure if missing versus an explicit error.

    The overlap was significant. Most of what dialers need from a lead record is the same: company name, contact name, phone number, address, state, some kind of category or industry tag. The differences were in naming conventions and field formats, not in the underlying information.

    This observation led directly to the most important structural decision in the whole pipeline.

    Golden Columns

    If multiple downstream systems all need roughly the same information, and the variation is in format rather than content, then there exists a canonical representation of a lead record that can be transformed into any downstream format without data loss.

    I called this the Golden Columns.

    The Golden Column set was the formal expected schema that a lead record had to conform to before it could go anywhere. Not the format any one system needed — the superset of everything any system might need, normalized to a single consistent representation. Once a record was in Golden Column format, outputting it for any dialer or the CRM was a transform, not a reconstruction.

    This was the moment the project stopped being a collection of data-cleaning scripts and started being a pipeline.

    A pipeline needs a contract. The contract defines what goes in, what comes out, and what the shape of the data is at each stage. Before the Golden Columns, I had tools. After them, I had stages. That’s a different thing. Tools are independent. Stages are composable. You can chain stages. You can add a stage without breaking the others. You can test a stage in isolation.

    The pipeline design followed from the contract almost automatically.

    Twelve Steps

    By the time I had formalized the Golden Columns, I could see the full shape of what the pipeline needed to do to take raw third-party lead data to a dialer-ready output. I wrote it out as an ordered sequence:

    Encoding detection and normalization. BOM handling. Field presence validation against the Golden Column set. Company name fuzzy deduplication. Phone number parsing and format normalization. Address standardization. State code normalization. Industry and category tagging where present. Missing field handling and defaults. Golden Column output generation. Dialer-specific format transforms. Final validation pass.

    Twelve steps. Each one a discrete, testable operation. Each one necessary. Each one the result of a specific failure or discovery from the months of one-off processing that came before.

    671,000 records. Six minutes and thirty-two seconds.

    The speed came from the architecture. When every step is a discrete operation on a structured dataset — not a row-by-row loop, not a nested conditional mess, but a vectorized operation on a typed frame — the performance is a consequence of the design, not a separate optimization pass. I profiled it anyway. The bottleneck was where I expected it: the fuzzy matching at scale. I gave it more room to work in batch rather than iterating. The number dropped.

    6:32. That became the baseline.

    The Lesson That Took Twelve Steps to Learn

    I didn’t design this pipeline. I discovered it.

    Every tool in it started as a one-off fix for a specific problem I hadn’t anticipated. The fuzzy scrubber came from the franchise duplicate problem. The encoding handler came from the corruption problem. The Golden Columns came from the multi-system formatting problem. The BOM handler came from a hex editor at 9am wondering why a column name that was clearly visible was unreadable by my parser.

    None of it was planned. All of it was necessary.

    That’s how real data infrastructure gets built in practice: not from a design document, but from an accumulation of problems that eventually reveal the shape of the system underneath them. The design document comes after, when you’ve seen enough of the problems to know what the system is actually doing.

    The danger is stopping before you write the design document. If I’d kept the twelve steps as twelve separate scripts, I’d have twelve places to maintain, twelve places to break, twelve things to run in the right order from memory. The pipeline consolidates that into one process with a contract.

    The Golden Columns are that contract. Once you have a formal expected schema for your data, you have something you can build a tool around instead of continuing to improvise around a problem.

    The twelve steps were the improvisation. The pipeline was the design.

    The Processes Aren’t Proprietary. The Problems Are Universal.

    These patterns aren’t specific to one system or one company. They’re the natural result of working with third-party lead data at scale, and the order you build them in will follow the same logic regardless of your stack or your source.

    The fuzzy deduplication problem exists everywhere franchise and regional data gets aggregated. The encoding problem exists everywhere data crosses system boundaries. The multi-system schema problem exists everywhere more than one downstream consumer needs the same upstream data in a different format.

    The specific implementation I built is tuned to a specific set of systems, specific dialer configurations, specific CRM expectations. But the architecture transfers: identify your downstream schemas, define your canonical representation, build each cleaning step as a discrete testable stage, measure the output.

    The twelve steps I landed on were the twelve problems I encountered. Your twelve steps will be different. But you’ll encounter the BOM file. You’ll encounter the franchise duplicate problem. You’ll hit the moment where two systems need the same record formatted two different ways and you realize you’ve been solving the wrong problem.

    When you get there, you need a contract. Define what a clean record looks like before you worry about what any specific system needs from it. Everything else follows from that.

  • How to Automate Call Log Extraction from Convoso

    Convoso’s built-in export is manual. You select a campaign, pick a date range, download a CSV, and repeat for every campaign you’re running. If you need logs across multiple campaigns for multiple days, that’s a lot of clicks for data that should be arriving automatically. Here’s how to schedule the extraction so the files are waiting for you rather than you waiting to pull them.

    ## Why Manual Log Extraction Breaks Down

    Call log data is most useful when it’s fresh and structured. The manual export workflow in Convoso produces it late and inconsistently — downloaded when someone remembers, formatted differently depending on who pulled it, sitting in someone’s Downloads folder instead of a shared location.

    The downstream cost is real. Analysis built on manually-pulled CSVs is always lagged. If your team is doing performance reviews, list quality assessments, or compliance checks from call log data, the gap between when calls happen and when the data is available affects the decisions you can make.

    Automation closes that gap. Scheduled nightly extraction means the data for today’s calls is available before tomorrow’s floor opens — without anyone pulling it.

    ## How Automated Extraction Works

    Convoso exposes call log data through its API. The automated version runs on a schedule — nightly works for most operations — authenticates against the API, pulls records for each active campaign across the target date range, normalizes the output, and deposits structured files to a shared location.

    The typical output format is Parquet for analytics pipelines or CSV for teams using spreadsheet-based reporting. Both are straightforward from the API response.

    **What the automation handles:**

    – Authentication against the Convoso API using a stored token
    – Pagination across large date ranges — Convoso returns logs in pages and large pulls require iterating through all of them
    – Multi-campaign extraction in a single run
    – Format transformation from API response to your target schema
    – Deposition to a shared server location, cloud storage bucket, or data warehouse staging area

    The result: call logs for every active campaign, normalized and deposited, on a schedule you define — without anyone touching an export button.

    ## The Complication: Silent Partial Extraction

    The Convoso API is well-documented, but there’s a failure mode that’s easy to miss and hard to detect after the fact.

    Convoso rate-limits API calls. When you hit the rate limit mid-pagination — while iterating through a large date range across multiple campaigns — the API may return a 200 response with partial data rather than an explicit error. The extraction completes, the file looks plausible, and you have no immediate signal that records are missing.

    This is the worst kind of failure for compliance and analytics use cases. If you’re using call logs to verify DNC processing, agent activity, or disposition accuracy, a partial extraction that looks complete is more dangerous than a failed extraction that surfaces an error.

    **The correct implementation handles this in two ways:**

    First, explicit rate limit handling with backoff — rather than firing requests as fast as possible, the extractor respects Convoso’s limits, detects rate limit responses, and retries with appropriate delays before continuing pagination.

    Second, record count validation — before writing the output file, the extractor compares the pulled record count against Convoso’s reported total for that campaign and date range. If the counts don’t match, the run fails loudly rather than writing an incomplete file.

    A partial extraction that writes silently is a data quality problem waiting to surface in an audit. An extraction that fails loudly is fixable in the next run.

    ## What the Architecture Looks Like

    **A scheduled job** — Cloud Run jobs work well for this (runs on schedule, no server to maintain), but a cron job on an existing server or a scheduled GitHub Action also works. The key requirement is reliable scheduling and logging.

    **Authentication management** — the Convoso API token needs to be stored securely (environment variables or a secrets manager, not hardcoded) and the extraction needs to handle token expiry gracefully.

    **Pagination logic** — pull records in pages, iterate until the total matches, fail loudly if it doesn’t.

    **Output normalization** — Convoso’s API response includes fields your analytics layer may not need and structures data in ways that don’t map cleanly to your schema. A transformation step before writing produces consistent output regardless of API response variations.

    **Deposition** — whether you’re writing to a shared network location, a Google Cloud Storage bucket, or staging tables in a data warehouse, the deposition step should include a manifest file: extraction timestamp, campaign IDs covered, record counts, and any warnings. This is your audit trail for the extraction itself.

    ## Frequently Asked Questions

    **Does this work for all Convoso campaigns, or do I have to specify each one?**
    You specify which campaigns to extract from during setup. Most operations extract from all active campaigns, but you can configure exclusions — campaigns used for testing, inactive campaigns, or campaigns managed by a different team.

    **How do I handle date ranges? Can I pull historical data?**
    The same extractor handles historical pulls — you pass a different date range parameter. Historical pulls for large date ranges need the pagination and rate-limit handling to be solid, since they’re pulling substantially more data than a nightly incremental run.

    **What format should the output files be in?**
    Parquet is the best choice if you’re loading into a data warehouse or analytics pipeline — it’s compressed, typed, and fast to query. CSV works if your destination is spreadsheet-based reporting. The format should match where the data is going, not what’s easiest to produce.

    **Can this run more frequently than nightly?**
    Yes, though most operations don’t need intraday extractions — the data isn’t meaningfully different from what Convoso’s real-time reporting surfaces. Nightly is the right default for analytics and compliance use cases.

    ## If You’d Rather Have This Running

    I build automated call log pipelines for contact centers using Convoso. If you want scheduled extraction, normalized output, and validation logic that fails loudly rather than silently — start here: rfditservices.com/intake.html

    The first conversation is free.

  • How to Forecast End-of-Day Call Center Performance

    By mid-afternoon, you can know where your floor will close by end of day — accurately enough to make the remaining hours a decision, not a guess. Here’s how intraday performance forecasting works and what it takes to build it.

    ## The Problem With Yesterday’s Numbers

    Most contact centers have end-of-day metrics. Dials, connects, conversion rate against target. Those numbers are accurate, useful for trend analysis, and arrive the next morning.

    By the time you see them, the day is already over.

    The decisions that drive outcomes happen during the day — in real time, when hours remain to influence the result. Do you push harder in the final stretch? Adjust campaign priority? Pull a server that’s underperforming? Those decisions get made in the afternoon with one question underneath all of them: where are we going to close?

    If you’re answering that question with yesterday’s data and experienced intuition, you’re working with an information deficit that compounds every day it stays open.

    ## How Intraday Forecasting Works

    The system records dial conversion rates at regular intervals throughout the business day. Not a snapshot at end of day. A continuous read of how the floor is performing as it performs.

    Every morning, before the floor opens, the model retrains. It processes the intraday conversion patterns from previous days — how conversion tends to develop through the morning, when it typically accelerates, when it softens, how afternoon performance differs from morning — and calibrates to the current operation’s historical data.

    As the day runs, the forecast updates on a regular schedule. Each update incorporates actual conversion data that’s come in, narrowing the prediction window.

    By mid-afternoon, with hours remaining, the model’s error range has compressed enough that the closing metric is predictable within an actionable range. Not a rough estimate. A forecast with a documented accuracy track.

    **What this changes in practice:**

    Before the forecasting system, the afternoon conversation was backward-looking: here’s where we are, here’s where we were yesterday, here’s the gap. The decision about the next few hours was judgment — experienced judgment, but judgment without a forward projection.

    After the forecasting system, the afternoon conversation is forward-looking: here’s where we are, here’s where we’re going to close, here’s what the remaining hours need to produce to change that number. The judgment still applies. But it’s informed by a projection that’s been validated against actual outcomes rather than intuition alone.

    That’s a different kind of management posture. You’re not reacting to what happened — you’re positioned in front of what’s about to happen.

    ## The Complication: Point Estimates Break When You Need Them Most

    The obvious version of intraday forecasting — average dial conversion rate over recent days, extended to end of day — works in normal conditions and breaks exactly when conditions are abnormal.

    Days after holidays follow different patterns than regular days. Days with agent attrition don’t produce the same intraday curve as fully-staffed days. A mid-day list quality shift — new inventory loading into an active campaign in the afternoon — changes the conversion trajectory in ways a backward-looking average can’t capture.

    A point estimate that’s wrong on the days that matter most is useless. Operations managers stop trusting a forecast that fails them when they need it, which is precisely when conditions are unusual.

    **The correct implementation produces a confidence interval, not just a point estimate.**

    A point estimate says: we’ll close at X conversions.

    A confidence interval says: we’ll close between X and Y conversions, based on current trajectory and historical variance.

    The confidence interval tells you two things the point estimate doesn’t. First, it tells you when the day is trending outside normal bounds — when the interval is wider than usual, the model is operating in territory with less historical precedent, which is a signal to pay attention. Second, it tells you when a result is well-constrained versus genuinely uncertain — a narrow interval with hours remaining means the outcome is largely determined; a wide interval means the remaining time is more variable than usual.

    **Additional inputs that improve accuracy:**

    Day-of-week weighting. Each day’s patterns should be compared to its own history, not the full week averaged together. The model needs to know what kind of day it is.

    Agent count as a real-time input. Utilization affects conversion. A floor running below normal staffing has a different conversion profile than a full floor, and the model needs to account for that explicitly rather than absorbing it as noise.

    ## What Building This Requires

    **A data collection layer.** Conversion rates pulled from your dialer API at regular intervals throughout the day, stored with timestamps. Convoso’s API supports this; a scheduled script on a consistent cadence collects the signal reliably.

    **A retraining pipeline.** Each morning, before the floor opens, the model fits to historical intraday patterns. The features that matter most: time of day, day of week, agent count, and recent conversion velocity. A well-structured ML regression model with the right features outperforms a complex one with the wrong ones — the goal is a forecast accurate enough to act on, not a showcase of modeling sophistication.

    **Validation tracking.** The model’s predicted closing range logged against actual outcomes, daily. This is how you know when the model is drifting and needs recalibration, and it’s how you build the track record that makes the forecast worth trusting. A model you’ve been validating for several months has a credibility that a newly deployed model doesn’t.

    **A delivery layer.** The forecast needs to appear where ops managers look — a dashboard, a scheduled Slack message, a Google Sheets integration. A forecast nobody sees is the same as no forecast.

    ## Frequently Asked Questions

    **How accurate is the forecast by mid-afternoon?**
    Accurate enough to make the remaining hours actionable rather than reactive. The exact precision depends on your operation’s historical variability — a stable floor with consistent staffing and consistent list quality will have tighter forecast intervals than one with high day-to-day variance. The value isn’t in the precision of the number — it’s in the direction and whether you’re trending toward or away from target.

    **Does this require machine learning expertise to build?**
    The approach is an ML regression model with appropriate feature engineering — time of day, day of week, recent velocity, agent utilization. The complexity is in getting the features right and building the validation discipline, not in the modeling approach itself.

    **What data do I need to start?**
    Historical intraday data at the interval you want to forecast at — ideally several months of regularly sampled conversion rates. If that data isn’t archived, starting with collection now and building the model after accumulating enough history is the right sequencing.

    **Can this work if our staffing varies a lot day to day?**
    Yes, but agent count needs to be an explicit input to the model rather than something it absorbs implicitly. Days with unusual staffing should be labeled as such in the training data so the model can account for the pattern, rather than treating them as noise.

    ## If You’d Rather Have This Built

    I build intraday performance forecasting for contact centers. If you want the data collection, the retraining pipeline, and a confidence-interval forecast that surfaces where your floor will close before the last hours are gone — start here: rfditservices.com/intake.html

    The first conversation is free.

  • How to Monitor Dialer List Health in Convoso

    Your list is degrading right now. Aged leads, disconnected numbers, leads that already converted on a different campaign, numbers that hit DNC since you imported them — all of them are burning dial attempts and suppressing your contact rate. Here’s how to build the monitoring layer that surfaces this before it collapses your numbers.

    ## Why List Health Degrades Faster Than You Think

    A fresh lead list has a predictable contact rate. As it ages, that rate decays — but not linearly. The first pass reaches the easiest contacts. Each subsequent pass hits harder-to-reach numbers, people who’ve already heard the pitch, numbers that have gone stale since import. The decay curve accelerates as penetration increases.

    Most Convoso operations notice this as “the list is getting old” and respond by ordering more inventory. The actual problem usually sits earlier: the campaign’s penetration rate wasn’t being tracked, import hygiene missed duplicates against existing leads, and the warning signs were invisible until the contact rate had already collapsed.

    A 10% drop in contact rate over a week is expensive. A 30% drop is a bad week. Neither one is a surprise if you’re monitoring the right signals before they hit.

    ## What List Health Monitoring Tracks

    The metrics that matter, in roughly the order they’ll help you:

    Penetration rate by campaign. What percentage of imported leads have been attempted at least once? This is the leading indicator — the one that gives you time to act. When penetration reaches a threshold, you need new inventory in the pipeline before the campaign goes hungry, not after agents are sitting idle. Convoso doesn’t surface penetration rate prominently in its standard reporting. You have to calculate it from the data the API exposes.

    Contact rate by lead age. Track conversion not just in aggregate but broken down by how long ago a lead was imported: leads attempted in week one, week two, week three since import. The decay curve tells you when a list is effectively exhausted from a productivity standpoint, even if numbers technically remain. Most operations have more “leads” than viable leads — the monitoring makes that distinction visible.

    Lead aging distribution in active campaigns. A campaign can look healthy on aggregate while its active pool is dominated by weeks-old records. Breaking it down by import age surfaces this before it becomes a contact rate problem.

    Cross-campaign duplicate exposure. A number active across multiple campaigns creates agent confusion, customer frustration, and wasted attempts. Deduplication at import catches most of this; monitoring catches what slipped through and surfaces it before it compounds.

    ## The Complication: Convoso Shows You the Past

    Convoso’s built-in reporting is backward-looking. It shows you what your contact rate was yesterday, what it was last week, how many dials converted over any given period. That data is genuinely useful for trend analysis, period comparisons, and reporting to management.

    It doesn’t tell you what your contact rate is going to be in two hours if the list doesn’t change.

    The monitoring that prevents a bad afternoon is penetration rate tracking updated in near-real time, not an end-of-day summary. When a campaign’s available-to-dial leads drop below a threshold, you want to know while there’s still time to load new inventory and have it processing before the afternoon push — not the following morning when the opportunity is already gone.

    Building that leading indicator requires pulling data Convoso doesn’t surface in standard dashboards. A scheduled pull from the API at regular intervals, tracking available lead count by attempt history, gives you the penetration picture as it develops. Cross that with contact rate by lead age and you have a system that surfaces degradation while there’s still time to respond.

    The second complication is at import time. A list that wasn’t scrubbed against existing leads, recent DNC additions, and disconnected numbers before it loaded starts its decay already in progress. Monitoring will surface this — you’ll see the contact rate compress faster than expected for a fresh list — but prevention is cheaper than remediation. Import hygiene automation that runs before the first dial is the companion to monitoring that makes the numbers meaningful.

    ## What the Monitoring Layer Looks Like in Practice

    A scheduled data pull from the Convoso API capturing campaign-level lead counts, attempt history, and contact rates at regular intervals. This doesn’t require a dedicated monitoring platform — the API exposes the data and a scheduled script can collect and log it reliably.

    A dashboard that surfaces threshold violations. A Google Sheets integration works for most SMB contact centers: data lands in a structured format, conditional formatting flags penetration thresholds, and a shared sheet gives ops managers visibility without requiring a new tool. Slack alerts on threshold crossings add a push notification for the signals that need immediate attention.

    Defined thresholds calibrated to your operation. The metrics that signal a list health problem aren’t universal — the right numbers come from your own historical baselines. But the framework is consistent across operations:

    – Contact rate significantly below your historical baseline: urgent flag — the list is exhausted or degraded and is burning agent time without result
    – Contact rate in a healthy range for your vertical and lead source: the target for a well-managed list with appropriate aging
    – Conversion rate below a minimum threshold: list quality problem — leads aren’t converting at a rate that justifies continued dialing; source quality or aging is the likely cause
    – Conversion rate at or above your operational target: the performance level a fresh, properly sourced list should sustain

    Establish your own baselines from the first few weeks of monitored data. The monitoring layer tells you when you’re deviating from those baselines — the thresholds you set determine when deviation triggers an alert.

    Import hygiene automation. Pre-import scrubbing against your existing lead pool and DNC sources reduces the decay rate before the first attempt. This is prevention rather than monitoring, but it’s the step that makes the monitored numbers worth tracking.

    ## Frequently Asked Questions

    Does Convoso have any built-in penetration tracking?
    Convoso shows attempt counts and disposition breakdowns, but not penetration rate as a campaign-level health metric calculated against total imported leads. You derive it from the data the API exposes — available leads versus total leads in the campaign.

    How often does the monitoring need to run?
    For most operations, regular intervals give you enough resolution to catch degradation while there’s still time to act. Running it more frequently is possible but usually doesn’t change the response time meaningfully.

    What if we’re pulling from multiple lead sources with different quality profiles?
    The monitoring should track by source where possible, not just by campaign. A list from one source may have a different expected decay curve than another. Blending them without source tagging makes the contact rate signal harder to interpret.

    ## If You’d Rather Have This Running

    I build monitoring layers for contact centers using Convoso and similar platforms. If you want penetration tracking, contact rate dashboards by lead age, and threshold alerting set up correctly — start here: rfditservices.com/intake.html

    The first conversation is free.

  • How to Automate DNC Removal Requests in Convoso

    DNC removal requests shouldn’t take more than a few seconds to process. If your ops team is manually logging into each system, finding the number, and removing it one platform at a time, every request is an open compliance window. Here’s how to close it automatically.

    ## The Problem With Manual DNC Processing

    A number comes in flagged for removal. Someone on the floor submits it. If you’re running Convoso alongside Zoom Contact Center, Zoom Phone, and Telesero, that means logging into each system separately — find the number, remove it, move to the next platform, repeat.

    At multiple removal requests per week across several systems, you’re looking at significant manual work each week. More importantly, every minute between the request and the removal is a minute of active compliance exposure. A TCPA violation starts at $500 per call. When the pattern is systematic — a number that should have been removed staying active across multiple campaigns — class action exposure enters the picture.

    The gap between when a removal is requested and when it actually completes isn’t just inefficiency. It’s risk that compounds with every dial attempt on a number that should be off the list.

    ## How Automated DNC Removal Works

    The automated version uses a Slack slash command as the intake point. An ops manager types the number into a command and hits send. The request routes immediately to a cloud service — deployed on Google Cloud Run — that fans out across every active system in parallel.

    Not sequentially. Simultaneously.

    In a contact center running multiple Convoso campaigns alongside Zoom Contact Center, Zoom Phone, and Telesero, a single command hits every platform in parallel. Each system processes the removal independently. Results log to cloud storage with a timestamp and each system’s individual response recorded separately. A confirmation returns to the Slack channel before the manager has switched back to their next task.

    Wall-clock time from submission to confirmed removal across all systems: under three seconds.

    What you get:

    – No manual steps across multiple logins
    – Every system processes simultaneously, not sequentially
    – An audit trail in cloud storage for every request — number, timestamp, and each platform’s response logged individually
    – Confirmation back to Slack showing exactly which systems confirmed the removal

    This is hours of manual work eliminated and a compliance window that closes in seconds instead of sitting open for minutes or hours.

    ## The Architecture

    The core components are straightforward:

    A Slack slash command configured to accept a phone number and POST it to your backend service. Slack’s platform makes the setup straightforward — the command sends the number to a URL you control.

    A cloud service (Cloud Run works well here — costs are minimal at typical contact center request volumes) that receives the number, authenticates with each dialer platform, and fans the removal request out in parallel. The service holds valid API credentials for every system in your stack.

    Cloud storage logging that records every request: the number, the timestamp, the system, and the response. This is your audit documentation. If compliance ever needs to verify a removal, it’s timestamped and searchable.

    ## The Complication Most Automated DNC Tools Miss: The Litigator List

    Most contact centers treat DNC compliance as “scrub against the Federal registry.” That’s necessary but not sufficient — and the list that’s actually generating settlements isn’t the Federal DNC list.

    It’s the litigator list.

    Serial TCPA plaintiffs — professional litigants who specifically target contact centers for violations — maintain numbers that don’t appear on the Federal or state DNC registries. They’re not on any opt-out list. They’re on a separate database of known litigators tracked by services like Blacklist Alliance, Contact Center Compliance’s Litigator Scrub, and IPQS. These databases are updated from court records as new cases are filed.

    A number that’s not on the Federal DNC registry, not on any state list, and has no internal opt-out record can still be held by someone who files TCPA suits as a business model.

    The correct scrubbing sequence for every removal request — and for every new list before import — is:

    1. Federal DNC registry
    2. State DNC lists (Florida’s FTSA and California have stricter requirements than federal)
    3. Litigator list (Blacklist Alliance, Contact Center Compliance, or equivalent)
    4. Internal opt-out list

    Most automated DNC tools only run step one. Some run steps one and two. The ones that skip the litigator scrub are leaving the highest-risk exposure in place.

    The second complication: graceful failure is the wrong behavior for compliance tools.

    After a DNC tool deploys, it’s easy to assume it’s working correctly. Confirmations come back clean. The Slack channel looks fine. The process appears to be running.

    The hidden failure mode: most automation handles errors gracefully. When a system fails to process a removal — expired credentials, missing API token, network timeout — the default behavior is to log the error internally and continue. The confirmation that returns to the manager says the request was processed. It doesn’t say one of the systems was skipped.

    A DNC tool that ran for several weeks while silently skipping one of its Convoso campaigns — because the API token had never been added to the deployment configuration — reporting clean confirmations the entire time, is a real scenario. The removals were going through on every platform except one. The audit trail showed success. The problem was invisible until someone looked at the deployment configuration directly.

    The correct implementation fails loudly. If any single system doesn’t return a confirmed removal, the tool surfaces a failure — not a partial success, not a warning in a log file no one checks. A visible failure in the Slack channel, requiring someone to act on it.

    A single-point failure that gets surfaced immediately is fixable. A multi-week silent failure discovered in a compliance audit is expensive.

    ## Frequently Asked Questions

    Does this work if we have multiple Convoso campaigns?
    Yes. The service authenticates against the Convoso API and processes the removal across every active campaign in your account. You specify which campaigns are in scope during setup — typically all active campaigns, with exclusions for any that aren’t applicable.

    What happens if one system is down when a removal request comes in?
    The tool surfaces a failure for that system specifically, while confirming removals on every other platform that processed successfully. The manager knows exactly which system needs follow-up, rather than assuming the removal is complete.

    Is the audit trail sufficient for TCPA compliance documentation?
    The audit trail records the number, the timestamp, and each system’s individual response. Whether that meets your specific compliance documentation requirements depends on your legal setup — this is worth confirming with compliance counsel, but the structure is designed to produce a clear, searchable record of every removal.

    What does this cost to run?
    At typical contact center request volumes, Cloud Run costs are minimal — the service only runs when a request comes in. Cloud storage logging adds cents per month at that volume.

    ## If You’d Rather Have This Done

    I build this kind of compliance automation for contact centers. If you want the Slack command, the cloud service, the audit trail, and the failure handling set up correctly from the start — start here: rfditservices.com/intake.html

    The first conversation is free.

  • The Insight Lens: Building Chrome Tools for Contact Center Teams

    The Insight Lens: Building Chrome Tools for Contact Center Teams

    Most workplace software was built for someone else’s workflow.

    I work in high-volume digital marketing. The tools we use — Convoso, Telesero, various CRMs — are built for general audiences, which means they’re never quite right for any specific team’s actual process. Managers get report portals that are hard to read and impossible to print. Agents get interfaces with small frictions that compound across hundreds of calls a day. Scheduling runs on whatever the vendor decided was sufficient.

    So I build tools.

    The first one came from a simple request: a manager on the scheduling side needed to present agent performance reports to stakeholders, and the vendor portal printed badly. I built a Chrome extension that reformats the output into something clean and readable. The vendor’s UI is still clunky. The reports look professional now.

    The page refresher was even simpler. The team needed an auto-refresh tool. The right answer wasn’t a third-party extension — those tools read browser data, and I wasn’t willing to risk company information for convenience. The private version took ten minutes to build and doesn’t touch anything it doesn’t need to.

    The dialing tools are the ones that add up. An agent on Telesero or Convoso might handle 150 to 400 calls in a day. Shaving three seconds off each one recovers somewhere between seven and twenty minutes per agent per day. I’ve built several of these — small quality-of-life upgrades that make each dial slightly faster, each disposition slightly cleaner. Across a team, the math compounds.

    The ambitious one was a remote coaching tool — filling a gap between what the two vendor platforms offered separately and what the team actually needed when working them together. Still in progress.


    The lesson isn’t about Chrome Extensions. It’s about proximity. Being close enough to the actual work to see the friction, and skilled enough to do something about it. That combination — operational context plus technical ability — is rarer than either one alone.

  • Automating Most of My Job: I Didn’t Want to Babysit a Dialer Forever

    I Didn’t Want to Babysit a Dialer Forever

    The unglamorous version of data administration is a lot of watching. Watching a dialer load leads. Watching a queue fill and drain. Watching the same manual processes run the same way they’ve always run because no one has had time to change them.

    I didn’t want to do that indefinitely.


    The first experiments were messy. Early Google Gemini API calls combined with Python Selenium — browser automation that could handle the dialer interactions I was tired of doing myself. The code was fragile, the model was still finding its footing, and the results weren’t perfect. But they were good enough to prove something: the repetitive parts of this job could be handled by something that wasn’t me.

    That realization changed what I built next.


    The Telesero Balancer is the clearest example — a live system that handles the distribution logic I used to manage manually. Convoso tools that shave seconds off agent workflows at scale. Brownbook Tools for the data sourcing problem. External partnerships that bring in raw lead data without someone manually pulling it.

    None of these have a clean ROI number attached. I haven’t measured hours saved per week and multiplied by fifty-two. What I can say is that the class of work I was doing when I started — the babysitting — occupies a fraction of the same time, and what replaced it is more interesting.