// Follow-up Due Today
// SYNCING...
[ NO SIGNAL ]
No session loaded.
Go to Import → paste Gemini JSON → hit Load. Takes 10 seconds.
Import Method
1Generate JSON using Gemini or Claude
Copy the prompt below → open Gemini (gemini.google.com) or Claude (claude.ai) → paste the prompt along with your copied sheet rows → copy the resulting JSON here.
gemini_prompt.txt
CRITICAL: First, filter out and ignore all rows where "Call Status" is "Not Called". Only perform the JSON analysis, calculations, and lists on rows where "Call Status" is NOT "Not Called" (i.e., those where a call was actually made). Do not analyze or summarize columns (like Target Tier, City, or License Type) for any uncalled rows, and do not write a summary report. Return ONLY a valid JSON object matching the schema below. No explanation, no markdown, no code fences. Just raw JSON starting with { and ending with }. Use exactly this structure: { "date": "YYYY-MM-DD", "calls_made": number, "not_called": number, "showed_interest": number, "follow_up": number, "not_interested": number, "no_pickup": number, "left_vm": number, "disconnected": number, "closed": number, "interest_rate_pct": number, "pickup_rate_pct": number, "trades": [ { "name": "trade name", "called": number, "interested": number, "follow_up": number, "left_vm": number, "not_interested": number, "no_pickup": number } ], "objections": [ { "text": "short description of objection", "count": number, "example": "one real quote or paraphrase from notes" } ], "followups": [ { "business": "business name", "trade": "trade", "phone": "phone or empty string", "status": "Showed Interest or Follow Up", "heat": "hot or warm or cold", "genuine_interest": true or false, "license_age_days": number or null, "timestamp": "value from the Timestamp column for this row, exact string, or empty string if blank", "follow_up_date": "MM/DD/YYYY if a specific calendar date can be confidently determined from the notes, otherwise empty string", "follow_up_time": "HH:MM in 24hr format if a specific time can be confidently determined, otherwise empty string", "prep_brief": "1-2 sentence actionable insight for the next call with this lead, based on their notes — read their psychology and suggest the angle to close the sale while staying on-brand. Empty string if there isn't enough in the notes to base this on.", "why_follow_up": "detailed explanation of why we are following up with the contractor based on their notes and conversation history (e.g., asked to review details, busy during summer, wants call-back after vacation, needs to talk to spouse/partner). Make this thorough and context-rich." } ], "dials": [ { "business": "business name", "phone": "phone or empty string", "timestamp": "value from the Timestamp column for this row, exact string, or empty string if blank", "status": "status string normalized to: No Pickup, Left VM, Showed Interest, Follow Up, Not Interested, Disconnected, or Closed", "state": "CA, WA, CO, OR, or ME", "trade": "trade name", "genuine_interest": true or false, "license_age_days": number or null } ], "priorities": ["Priority 1 as a plain sentence", "Priority 2 as a plain sentence", "Priority 3 as a plain sentence"], "session_notes": "2-3 sentence plain English summary of today" } Rules: - CRITICAL: Do NOT include summary reports, geographic summaries, or tier distributions in the JSON output. Strictly use the keys specified in the schema. - CRITICAL: Only count, analyze, or list rows where Call Status is NOT "Not Called". - Identify columns dynamically by reading the first header row. Find columns named "Call Status", "Notes", "IssueDate" (usually Column J), and "Timestamp" (usually Column L). - calls_made = rows where Call Status is NOT "Not Called" - not_called = rows where Call Status is "Not Called" - interest_rate_pct = showed_interest / calls_made * 100, rounded to 1 decimal - pickup_rate_pct = (showed_interest + follow_up + not_interested + closed) / calls_made * 100, rounded to 1 decimal - dials must include an object for EVERY row in the sheet where Call Status is NOT "Not Called". For each row, copy the business name, phone number, and the exact value from the "Timestamp" column. Normalize the Call Status strictly to one of these exact enums: "No Pickup", "Left VM", "Showed Interest", "Follow Up", "Not Interested", "Disconnected", "Closed". (For example, map raw spreadsheet values "Showed Intrest" -> "Showed Interest", and "Follow up" -> "Follow Up"). Do not use any other status names. For each dial: 1. Determine the state ("CA", "WA", "CO", "OR", or "ME") based on the prefix of the "LicenseNo" column (starts with "CA-" is CA, "WA-" is WA, "CO-" is CO, "OR-" is OR, "ME-" is ME). If the prefix is missing, fallback to the License Type or the phone area code/city. 2. Include the "trade" field normalized to the Title Case trade name (e.g. "Plumbing", "Electrical", etc.). 3. Set "genuine_interest" to true if Call Status is "Showed Interest", or if Call Status is "Follow Up" and the notes show genuine interest. Set it to false otherwise. 4. Calculate "license_age_days" as the number of days between the date in the "IssueDate" column (usually Column J) and the call date (today's date). If "IssueDate" is blank or invalid, use null. - followups must include ONLY rows with status "Showed Interest" or "Follow Up" — do NOT include "Left VM" rows in this array. - For rows with status "Follow Up": read the notes carefully and set "genuine_interest" to true if the person showed real curiosity, asked questions, or engaged meaningfully, even if they asked to be called back. Set it to false if it was a non-committal brush-off like "call me later", "not now", "too busy." Use your best judgment — this is a qualitative read. - license_age_days: Calculate the number of days between the date in the "IssueDate" column and today's date (the date at the top of this sheet or the session date). Include this as an integer on each followup row. If the "IssueDate" column is blank, missing, or unparseable, use null. - timestamp field = copy the exact value from the "Timestamp" column for that row with no reformatting. If it is blank or the column doesn't exist, use an empty string. Do not guess or invent a timestamp. - follow_up_date and follow_up_time: Read the Notes column for that row. You MUST act as the thinking layer to convert any follow-up mention (including relative ones like 'in 3 weeks' or 'in 2 months') into a concrete date in the US format "MM/DD/YYYY" (e.g., "08/23/2026"), using today's date (from the session date at the top of the sheet) as the absolute reference point. For any arbitrary relative timeframe (e.g. 'in N days/weeks/months'), perform the calendar math relative to the session date (e.g. 'in 3 weeks' -> session date + 21 days; 'in 3 months' -> session date + 90 days; 'in 2 months' -> session date + 60 days) to calculate the exact calendar date. ALWAYS output the calculated date strictly as "MM/DD/YYYY". NEVER output relative strings like "in a week" or "in 2 months". If there is absolutely no follow-up timing mentioned in the notes, use an empty string "". Never guess a date if there is zero timing context. - follow_up_time: Parse the time mentioned in the notes. Normalize it to a 24-hour hour and minute (e.g. "14:00" for 2 PM, "10:30" for 10:30 AM). If the note is vague or doesn't mention a follow-up time, leave follow_up_time as an empty string. - prep_brief: base this only on what's actually in the notes for that lead. Focus on their stated objections, hesitations, or interest signals, and suggest one concrete angle for the next conversation. Keep it short and practical, not generic sales advice. - why_follow_up: read the Notes column and provide a detailed reason/rationale for why the follow-up is requested or necessary. Explain what they said, what their situation is, and what we need to address or resolve during the follow-up. Be specific to the lead. - heat: "hot" = Showed Interest, "warm" = Follow Up with genuine_interest true, "cold" = Follow Up with genuine_interest false - Objections come ONLY from Notes of Not Interested rows — group similar reasons, and where the note explains WHY they dropped off, preserve that reasoning in the example field - Priorities must be specific and actionable, not generic - All numbers integers except the two _pct fields - Trade names MUST be strictly normalized to Title Case (e.g., "Plumbing", "Electrical", "Roofing", "HVAC", "Handyman"). Standardize any spelling variations or suffixes (e.g. "plumb", "plumber" -> "Plumbing"; "electrician", "electric" -> "Electrical"). - Return the JSON object as described above. AFTER the JSON, on a new line, if any row had a follow-up mention that was too ambiguous to confidently convert to a date (e.g. "call back soon", "maybe next week"), add one line starting with "NOTE:" describing which leads had unclear follow-up timing so the user can manually check. If nothing was ambiguous, omit this line entirely.
2Paste JSON into the box above
Copy everything Gemini returns above the "NOTE:" line if present, including the outer braces. Paste into the box at the top of this page → Load Session.
3Check Home daily, Deep Dive weekly
Home gives you the daily read. Deep Dive is where patterns show up — check it once a week, not every day.
// Month
Sun
Mon
Tue
Wed
Thu
Fri
Sat
Interest rate over time
// AWAITING DATA
All-time totals
// Session log
Pickup rate by hour of day
Pickup rate by day of week
Interest rate by license age at time of call
How many days after getting licensed did you call them, and did it matter?
Trade Performance Breakdown
Trade Intelligence & Insights
Objections — all-time
Export for Claude
Pulls your aggregated history — totals, trends, time patterns, objections, and your starred session notes — into one clean text block. Copy it and paste straight into Claude for coaching.
Caller Management
Caller Performance (All-time)
Caller Total Calls Interest Rate Connect Rate Last Active
Compare Employees vs Admin (Leo)
Employee Call Vol Delta Interest Rate Delta Connect Rate Delta Assessment
Master Leads CRM (Combined Follow-ups)
Business / Trade Phone Caller Temp Follow Up Prep Brief & Rationale
// CALLER SETUP & WORKFLOW GUIDE
How to Use This System
This guide walks you through everything you need to do — from first-time setup to submitting your calls every day. Follow each step in order. If you're doing this for the first time, start at Step 1.
1
First-Time Setup: Add the Auto-Timestamp Script
This is a one-time step. It adds a tiny invisible script to your Google Sheet that automatically records the exact time of every call the moment you mark a status. You only need to do this once per sheet.
Google Apps Script — copy this entire block
function onEdit(e) {
  var sheet = e.range.getSheet();
  var col = e.range.getColumn();
  var row = e.range.getRow();

  // Only fire for column H (Call Status), and skip the header row (row 1)
  if (col !== 8 || row === 1) return;

  // Only stamp if there's actually a status value
  var newValue = e.range.getValue();
  if (newValue === "") return;

  // Stamp current time in column L (Timestamp)
  var timestampCell = sheet.getRange(row, 12); 
  timestampCell.setValue(new Date());
  timestampCell.setNumberFormat("h:mm AM/PM m/d/yyyy");
}
How to install it:
  1. Open your Google Sheet.
  2. In the top menu bar, click ExtensionsApps Script.
  3. A new tab will open. Delete any code that's already in the box.
  4. Click the "Copy Script" button above, then paste it into the Apps Script editor.
  5. Press Ctrl+S (Windows) or Cmd+S (Mac) to save it.
  6. Close that Apps Script tab and go back to your sheet. That's it — you're set up.
2
Every Day: Log Your Calls & Write Your Notes
Do this for every single call you make, as you make them. Don't wait until the end of the day.
① Call the lead
Dial the phone number in the BusinessPhone column of your sheet.
② Pick the call result
Go to the Call Status column on that row and select what happened from the dropdown — No Pickup, Left VM, Showed Interest, Follow Up, Not Interested, etc. The timestamp will be stamped automatically.
③ Write detailed notes — this is critical
In the Notes column, write down exactly what happened on the call. The more detail, the better.

If they want a callback, always include the date and time:
"Wants a callback on July 15th at 10am to discuss pricing"
"Call back next Tuesday — he's with a customer right now"
"Not interested, said they already use another platform"

The system reads your notes to automatically schedule your follow-up reminders. If you don't write the date and time, your callback won't be added to the calendar.
3
End of Session: Submit Your Calls to the CRM
When you're done calling for the day, do the following to upload your data. This takes about 60 seconds.
  1. Go to your Google Sheet. Press Ctrl+A (Windows) or Cmd+A (Mac) to select the entire sheet, then Ctrl+C / Cmd+C to copy it.
  2. Come back to this CRM and click the IMPORT tab at the top of the page.
  3. Click GOOGLE SHEET ROWS (NO GEMINI).
  4. Make sure the Session Date is set to today's date.
  5. Click inside the large text box and paste (Ctrl+V or Cmd+V).
  6. Click ▶ PARSE & PREVIEW. Your call results will appear below.
  7. Review your follow-ups — you can adjust the heat level and timing — then click SAVE SESSION. Done!
📋 Using the Same Sheet Across Multiple Days
It's completely fine to use the same sheet for more than one calling day. When you do your Ctrl+A → Copy → Paste each day, make sure you select today's date in the Session Date field before you parse. The system only reads the rows you called — it ignores anything still marked "Not Called". Each day you submit is saved separately, so your history stays clean and accurate.
// Add New Caller