Guide

A COI tracking spreadsheet that actually holds up

Free, no email required. The columns below are the ones that turn out to matter, and the file is a header row you can fill in immediately.

Track each sub's expiry dates and, separately, whether you hold the endorsements — additional insured, waiver of subrogation, primary & non-contributory. Most sheets track only the dates, which is why they miss the thing that actually leaves you exposed.

Key takeaways

  • Track endorsements as their own columns, not as one 'compliant?' cell. Additional insured and waiver of subrogation are separate documents on separate policies; collapsing them into one Y/N is how a gap hides.
  • A date column beats a status column. "Compliant" is true until the day it silently is not; an expiry date tells you when without anyone updating it.
  • Add a `last_requested` column. It is the one that stops you chasing the same sub twice in a week — and the one nobody thinks to add until they have chased someone twice.
  • A spreadsheet is genuinely fine for a handful of subs. It stops being fine at the point nobody is reading it on the day a policy lapses, which is a people problem rather than a spreadsheet problem.

By the Sealinn team · 5 min read · Updated July 2026 · Written for general contractors

Download it

Download the template (CSV)

Opens in Excel, Google Sheets or Numbers. Header row only — no sample data, so nothing fake ends up in your real list. The first six columns are named so that if you later move to Sealinn, the same file imports in one step rather than being retyped.

What each column is for

The first six identify the subcontractor. The rest are what you are actually tracking. Nothing here is decorative — every column exists because leaving it out is a way people get caught out.

ColumnExampleWhat it is for
company_namePeak Roofing LLCThe subcontractor's legal business name — the one on the certificate, not the crew's nickname.
contact_nameDana RuizWhoever you actually call. Usually not the person who signs the subcontract.
emaildana@peakroofing.exampleWhere renewal requests go. One address per row.
phone512-555-0142Optional, but it is what you fall back on when email goes unanswered.
tradeRoofingRoofing, electrical, concrete. Useful for sorting; not used in any compliance check.
stateTXTwo letters. Workers' comp rules are state law, so this is the column that tells you which rules apply.
gl_expiry2027-03-31When the general liability policy runs out. This is the date that ends up mattering most.
wc_expiry2027-01-15When workers' comp runs out — or 'exempt' plus the date you verified the exemption.
auto_expiry2026-11-30Only matters if they drive to the site or haul for the job.
additional_insuredY (20 10 + 20 37)Y once you hold the endorsement copies — CG 20 10 for ongoing and CG 20 37 for completed operations. Not Y because the certificate has a tick in the ADDL INSD column.
waiver_of_subrogationY (both)Y once you hold CG 24 04 on the GL policy and WC 00 03 13 on the comp policy. They are two separate endorsements.
primary_non_contributoryYY once the wording is in the endorsement, not just in your subcontract asking for it.
w9_on_fileYY / N. Nothing to do with insurance; it is just the other thing you always end up chasing.
license_expiry2027-06-30If the trade is licensed in that state. Blank is fine when it is not.
last_requested2026-07-14The date you last asked. This is the column that stops you chasing the same sub twice in a week.
notesAgent sending 20 37 endorsementAnything the columns above cannot hold — which agent to call, what is still outstanding.
The template columns. The sample values are shown here only — the file itself is a header row.

The columns most sheets are missing

Nearly every tracking sheet has expiry dates. Far fewer have a column for each endorsement — and the endorsements are the part that decides whether you are actually covered. A certificate can show a tick in the ADDL INSD column while the endorsement that grants it was never issued; the ACORD 25 says of itself that it 'does not affirmatively or negatively amend, extend or alter the coverage afforded by the policies below.'

  • [Additional insured](/glossary/additional-insured) — and note it is two endorsements, not one: CG 20 10 for ongoing operations and CG 20 37 for completed operations. A sub with only the first leaves you uncovered for the defect claim that surfaces two winters later.
  • [Waiver of subrogation](/glossary/waiver-of-subrogation) — also two: CG 24 04 on the general liability policy and WC 00 03 13 on the workers' comp policy, added separately by the carrier.
  • [Primary & non-contributory](/glossary/primary-and-non-contributory) — usually wording inside the additional-insured endorsement rather than a separate page, which is exactly why it gets assumed rather than checked.

Mark the endorsement columns Y only when you hold the endorsement

Not when the certificate has a tick in the box. The tick is the agent reporting what they believe is true; the endorsement is the document that makes it true. Ask the issuing agent — the producer named in the upper-left of the certificate — for the endorsement copies. Asking the sub for a fresh certificate just re-reports the same thing.

The routine that makes it work

  1. Sort by the earliest expiry date. That is your list, and it re-sorts itself as dates pass.
  2. Pick a fixed day each week. The sheet does not fail because it is a spreadsheet; it fails because nobody opened it.
  3. Request early — 30 days out, not on the expiry date. A renewal certificate often takes the agent a week.
  4. Fill in `last_requested` the moment you send. It is what stops the second chase in the same week.
  5. File the endorsement pages somewhere you can find them on audit day, not just the certificate.

When a spreadsheet stops being enough

For a handful of subs on one job, this file and a weekly habit are fine, and you should not pay for software to replace them. The point it stops working is not a number of rows — it is the first week nobody opens the sheet. Nothing in a spreadsheet notices a date passing, so an expiry becomes a lapse quietly, and you find out when a claim arrives. Where a sheet holds up and where it stops is the fuller version of that trade, and what the lapse actually costs is the part that decides whether it matters.

If that is the failure you are trying to prevent, what a small GC actually needs is the buying question stated properly, and what to require before a sub starts is the checklist this sheet is tracking against.

Where this comes from

When the sheet stops getting opened.

Sealinn reads each certificate, checks it against your requirements, and chases the renewal before the date passes — so nobody has to remember to look.