Introduction
The campaign ended last week, but the announcement page is still up. If you run an e-commerce site, you have probably run into this at least once. When an expired discount or a sold-out perk is still on display, users reasonably assume the offer is still running.
This article walks through the big picture of a system that gives temporary pages and event galleries an expiration date, then takes them down automatically when that date arrives — no human involved. What parts it is made of, the thinking behind the design, and how day-to-day operations change. The finer details live in the related articles, so start here for the overall shape.
Why Leaving Old Pages Up Misleads Users
An expired campaign left online creates price mismatches
Publishing a campaign landing page or a sale announcement is the easy part. The work is in taking it down afterward. When things get busy, cleanup slides to the bottom of the list, and expired prices and perks keep showing.
Price mismatches are the costly ones. "The amount on your site was different" takes support time to resolve and chips away at that user's trust in you. Forgetting to take a page down isn't just a missed task — it belongs on the list of operational risks that touch revenue and credibility directly.
Checklists stop working the moment the person in charge changes
"We'll just delete it when it's over" sounds fine until several campaigns run in parallel. Then tracking which page comes down on which date becomes work in itself. The person in charge was off that day, the handover missed it, nobody remembered publishing it at all. Being careful doesn't reliably prevent any of that.
Internal checklists and reminders can patch the gap, but they depend on specific people and break down when staff change. Building something that doesn't lean on human attentiveness ends up being both the most reliable option and the least effortful one.
Decide when it disappears at the same moment you publish it
The approach that worked is simple: decide the lifespan of a page at the moment you create it. When publishing, you enter an expiration such as "valid through the end of March." From there the system watches the clock and retires the page when the time comes.
Instead of leaving cleanup as a task for future you, it becomes one extra field at creation time. Just reversing that order removes almost every case of stale content lingering. The point is to build it in as an input, not to enforce it as an operating rule.
Publishing is easy, but the takedown depends on whoever remembers it. Forget once and stale information stays up
Set an expiration when you publish. The system retires it automatically, and the cleanup task disappears
In short, cleanup moves from being a task you do later to being a value you set while creating the page.
The System Is Made of Three Parts
A place to store, a watcher, and a check at display time
There are three pieces here. First, storage that holds the content and its expiration date. Second, a scheduled job (cron — a mechanism that runs a process automatically at a time you choose) that checks expirations and retires content. Third, the check on the public page that decides whether to show it.
Each has its own job, which makes it easy to add features later or swap out one piece without touching the others. Keep this three-part set in mind and the individual articles become much easier to follow.
Protected by one-time codes Set body, images, expiration
Holds the content itself and the expiration date
Finds expired items and unpublishes them
After expiry: a notice or a 404
Put in one line: you create a page with an expiration in the admin screen, a daily job watches that expiration, and the public page checks it again every time someone opens it.
No database — just KV
A feature of this size didn't need a full database. Temporary pages and event galleries aren't numerous, and there are no complicated relationships between records. So the whole thing runs on Vercel KV (a key-value store — you give it one name and it hands back what you stored under it).
That drops table design, migration work when the data shape changes, and connection management entirely, which makes both launch and operation lighter. Build small, grow it if the need appears. For supporting features, that call pays off.
The admin screen is guarded by one-time codes
The admin screen that creates temporary pages obviously can't be open to anyone. At the same time, bolting full permission management onto a small internal tool would be overkill. So it's guarded with one-time password authentication (OTP — a disposable code delivered by email).
You enter the code that arrives and you're in, which keeps the risk of reused or leaked passwords low while staying quick to use. Matching the strength of the guard to the nature of the tool is the practical choice.
Deleting and Unpublishing Are Different Jobs
Removing the data versus flagging it as expired
There are two ways to make something disappear on schedule. One uses the KV store's TTL (Time To Live — you set a lifespan when saving, and the data is removed automatically once that time passes). The other has the scheduled job watch the expiration and flip a flag that takes the page out of public view.
Both stop the page from being visible, but what happens afterward differs. Is the data gone, or is it still there and simply hidden? Knowing that difference lets you pick the one your requirement actually calls for.
The table comes down to one question: do you want to show anything after expiry? That decides the method.
What to show when someone opens an expired page
What you return to a user who lands on an expired page matters more than you'd expect. A 404 (the response meaning the page doesn't exist) is one option, but for a URL that spread on social media and gets clicked later, "this page is no longer available" is the kinder answer.
With the flag approach, the data is still there, so switching to a notice is easy. Rather than treating expiry as instant deletion, deciding how the page ends gives you more room to work with.
If deadlines are day-level, once a day is enough
The expiration check runs once a day. You might wonder whether that's often enough, but campaign and event deadlines are nearly always day-level — "valid through this date" — and nobody needs minute-level precision.
Raising the frequency raises the number of runs and the monitoring that comes with them. Choosing a cadence that isn't excessive for the requirement is part of keeping the system light. For the rare content that truly needs to stop the second it expires, add TTL alongside it.
Design takeaways
Decide the lifespan at creation, and use TTL and the scheduled job for different jobs. Those two alone remove nearly every case of stale content staying visible. Aim for a setup where the system handles cleanup instead of you.
Summary
Auto-expiring content isn't a flashy feature. What it does is guarantee that old information doesn't stay up — through the system rather than through anyone's attentiveness. The more campaigns you run at once, the more you feel the relief of never having to take anything down.
Two things to remember. Decide the lifespan when you publish, and choose between deleting and hiding based on the use. Features like this — an admin screen plus a scheduled job — are also the kind of thing you can build alongside an AI agent, as long as you can describe clearly what you want it to do.
If you want the details, the articles below go deeper.
Managing Temporary Content with KV Storage
A lightweight design that manages content and expiration in KV without standing up a database.
Cron-Based Expiration and Access Control
Scheduled detection and unpublishing of expired content, plus how to handle access after expiry.
Use Cases for Disposable URLs
Practical patterns from private event photo sharing to limited-time landing pages and internal sharing.