A subscription and free-trial tracker built for the moment that always catches you off guard — the surprise charge after a forgotten trial. Coyote lives in your browser, watches the clock, pulses when a trial is about to bill, and pushes calendar reminders to wherever your calendar already syncs. The whole experience is local-only, no account, no signup — catch the trial before it bills.
Jacqueline Check out my GitHub Profile 🚀 Try the Live App
Coyote's brand is built around one idea: a calm desert at night, watching for what's about to bill you. Every design decision serves that mood.
| Color | Hex | Role |
|---|---|---|
| Midnight | #0F1419 |
Primary background — deep canyon at night |
| Coyote Gold | #E0A458 |
Primary accent — the moon, the eye, the price |
| Bone | #E8DCC4 |
Primary text — warm off-white, easy on tired eyes |
| Sage | #6B7257 |
Secondary accent — calm, hopeful |
| Clay | #C76847 |
Urgent state — pulses when a trial is under 24 hours |
The midnight-and-gold pairing is intentional. Most subscription apps go cold tech-blue. Coyote went warm-dark — the feeling of looking up at a night sky over a canyon, not staring at a server admin panel. The gold accent is exclusively reserved for prices, the moon mark, and active states; clay-red is reserved for urgency. Color carries meaning at every step.
| Typeface | Use | Why |
|---|---|---|
| Fraunces (700 italic-capable serif) | Wordmark, prices, status headings | Editorial gravitas — the serif italic in "Coyote" makes the wordmark unmistakable |
| Inter (400/500/600 sans) | Body, UI labels, buttons | Modern, neutral, screen-optimized — handles the utility |
| JetBrains Mono (400/500) | Countdown numerals | Tabular, monospaced — the seconds line up perfectly as they tick |
The typography pairs an italic serif (warmth, deliberateness) with a sans (utility, screen legibility) and a mono (data, precision). That three-voice contrast is the brand. Wherever you see Coyote in italic Fraunces with the gold middle "o," you know it's the same product. The gold "o" doubles as the moon — tiny, ownable, repeatable across icons, social posts, and screenshots.
This project was designed and built during Phase I of Thinking with AI at Next Chapter Apprenticeship. Each lesson fed directly into this build:
- Computational Thinking — Decomposing the project into independent units (state store, countdown ticker, notifier, calendar exporter), recognizing the recurring closure-based factory pattern, and abstracting the calendar reminder into three interchangeable paths (.ics, Google, Outlook) so the UI doesn't care which one the user picks.
- HTML / CSS / Forms — Semantic landmark structure, accessible labels with
forattributes throughout, mobile-first responsive layouts, three-up dashboard at 600px+ breakpoint, urgent-state pulsing animations withprefers-reduced-motionrespected. - JavaScript Fundamentals — Closure-based factory functions (
createSubscriptionStore,createCountdownTicker,createNotifier) keeping all state private;textContentfor every user-rendered field for XSS safety; URL sanitization that rejectsjavascript:,data:, andfile:schemes outright. - Debugging — Hunting a stuck-modal bug across multiple rounds and learning the hard way that
display: gridoverrides the browser's default[hidden]behavior — fixed with a.modal-backdrop[hidden] { display: none !important; }rule that has since become a permanent pattern.
The project demonstrates everything Phase II covered, deployed as a working PWA.
| Browser / Device | Status | Performance Notes |
|---|---|---|
| Google Chrome | ✅ Tested | Full support — countdown timers, notifications, PWA install, calendar export. |
| Microsoft Edge | ✅ Tested | Matches Chrome rendering engine exactly. |
| Firefox | ✅ Tested | Full feature support including notifications and .ics download. |
| Apple Safari (macOS) | ✅ Tested | Calendar files open directly into Apple Calendar with one click. |
| iPhone (iOS Safari) | ✅ Tested | Add-to-Home-Screen, Web Share Target, calendar imports to iCloud Calendar. |
| iPad / iPadOS | ✅ Tested | Responsive grids adapt correctly to tablet viewports. |
- Live Countdown Cards: Every subscription becomes a card showing days, hours, and minutes remaining. Numbers tick every minute with millisecond accuracy preserved across tab backgrounding via
requestAnimationFrame+ end-timestamp recomputation. - Pulsing Urgent State: When a trial drops under 24 hours, the card border pulses clay-red and the card moves to the top of the dashboard.
- Stat Dashboard: Three at-a-glance metrics — active trials, total monthly cost across active subscriptions, and ending-soon count. The Ending Soon card visually shifts to a warning state when anything's urgent.
- Web Share Target Capture: Coyote installs as a PWA on iPhone, Android, Mac, and Windows — and once installed, appears in your phone's Share menu. On any signup page, hit Share → Coyote, and the Add form opens with the URL and page title pre-filled. You only type the cost and trial-end date.
- Edit-in-Place: Each card has a ✎ button that opens the form pre-filled with current values. Modal title swaps to "Edit subscription," save button swaps to "Update," and the same card updates without creating a duplicate.
- One-Click Calendar Reminders: Each card has a 📅 button that opens a three-choice modal — Google Calendar, Outlook, Apple Calendar / Other (.ics). The reminder fires 24 hours before the trial expires.
- Browser Notifications: Optional permission-based system notifications fire when a trial enters the under-24-hour urgent window.
- Monthly Check-In: Once per calendar month, Coyote shows a soft summary toast on first visit — "You're tracking 3 subscriptions totaling $42.97/mo."
- PWA Installable: Add to Home Screen on iPhone, ⬇ Install button on Chrome/Edge desktop. Coyote becomes a standalone app with no browser chrome.
- Progress Persistence: All data saves to
localStorage— no account required, no server, nothing leaves the device. - Accessible Throughout: Every label uses
forattributes,aria-pressedtoggles correctly, keyboard navigation works for all controls, every animation respects@media (prefers-reduced-motion).
Coyote was built to know nothing about you that you don't tell it.
- No account, no signup. You can track subscriptions, get reminders, and export to calendar without creating an account or sharing personal information.
- Your subscriptions stay on your device. All subscription data, reminder preferences, and meta state are saved only in your browser's local storage. Clearing your browser data clears your subscriptions — nothing lives on a server.
- No server, anywhere. Coyote has no backend, no database, no API. It's a static site. Once your browser loads it, nothing else gets sent over the network.
- Calendar exports are local. When you click "Apple Calendar / Other," a
.icsfile is generated in your browser using the iCalendar standard and downloaded to your device. The file never touches a server. - Google Calendar / Outlook links open with your data in the URL so the calendar provider can pre-fill the event form — but the data is sent only to that provider, only when you click, and only with the fields you've already entered (service name, cost, expiration date, optional URL).
Coyote doesn't use cookies, doesn't track you, and doesn't have a database that stores anything about you.
- Frontend: Vanilla JavaScript (ES6+) — closure-based factory functions,
requestAnimationFramefor accurate countdowns,localStoragefor persistence,crypto.randomUUID()for stable IDs - Styling: CSS3 — Custom Properties, CSS Grid, Flexbox,
@keyframesfor the urgent pulse,clamp()for fluid typography, mobile-first responsive design with breakpoints at 480px and 600px - Typography: Fraunces, Inter, JetBrains Mono — Google Fonts
- PWA: Web App Manifest with
share_targetfor Android/Chrome share menu integration; service worker (sw.js) using network-first strategy with offline fallback - Calendar Standard: RFC 5545 iCalendar (
.ics) generated client-side — no library; includesVALARMblock withTRIGGER:-P1Dfor 24-hours-before reminders - Calendar URL Templates: Google Calendar's
action=TEMPLATEURL format and Outlook'srru=addeventdeeplink format — both fully URL-encoded withURLSearchParams - Notifications: Browser-native
NotificationAPI with permission gating, falls back to in-app toast when not permitted - Deployment: GitHub Pages — static site, automatic HTTPS, auto-deploy on every push to
main
- Land on the dashboard → see the Coyote wordmark with the gold "o" moon, three stat cards (active / monthly cost / ending soon), and a clean empty state if nothing's tracked yet
- Click "+ Add subscription" → modal opens with Service Name, Monthly Cost, URL (optional), Trial End Date, and a "Want me to remember this?" yes/no question
- Or share to Coyote from your phone → install Coyote as a PWA → finish a free-trial signup → tap Share on the confirmation page → pick Coyote → the form opens with URL and title pre-filled
- Save the subscription → a card appears with a live countdown ticking days/hours/minutes
- Watch the dashboard update → stats recompute, monthly cost totals across all active trials, urgent count tracks anything under 24 hours
- Click 📅 on any card → choose how you want to be reminded: Google Calendar, Outlook, or
.icsdownload for everything else - Click ✎ on any card → fix a typo or update the date without re-entering everything
- Receive your reminder 24 hours before the trial bills → from your calendar, your phone, your watch, wherever your calendar syncs
Coyote's reminder system is built on the principle that the most reliable reminder is one that lives outside Coyote. Browser notifications can fail when tabs are closed; calendar reminders fire from your phone, your watch, your laptop — anywhere your calendar already syncs.
| Choice | What Happens | Best For |
|---|---|---|
| Google Calendar | Opens calendar.google.com with the event pre-filled. User clicks Save. | Gmail and Google Workspace users (most personal accounts) |
| Outlook | Opens outlook.live.com with the event pre-filled. User clicks Save. | Outlook, Office 365, Hotmail users |
| Apple Calendar / Other (.ics) | Downloads a .ics file. Opens directly into the user's default calendar app. |
Apple Calendar, ProtonMail, Fastmail, anything else |
All three paths produce the same event — Coyote builds the data once and offers three ways to ship it.
For Mac users with iCloud Calendar enabled, the flow is genuinely magical:
- Click 📅 on a Coyote card on your MacBook
- Pick "Apple Calendar / Other"
- The
.icsfile downloads — double-click it - Apple Calendar opens with an "Add to Calendar" dialog. Confirm.
- The event syncs to iCloud automatically.
- Within seconds, the same event appears on your iPhone, your iPad, your Apple Watch — every device signed into the same iCloud account.
You don't repopulate anything. You don't email yourself. You don't open a separate app on your phone. macOS Calendar pushes the event up to iCloud, iCloud pushes it down to every device, and 24 hours before your trial bills, every screen you own is going to remind you.
This is the same .ics standard the entire calendar industry runs on (RFC 5545) — but the Apple ecosystem treats Coyote the same way it treats events from your job, your dentist, or your travel itinerary. Once the event is in your calendar, Coyote's job is done.
Every Coyote calendar event is built with the user in mind:
- Title: "Hulu trial ends — cancel or get charged $14.99" (the cost is right in the event title)
- Time: 1-hour block ending at the trial expiration so you can see it on your day view
- Description: Clear next-action language ("Cancel before this time if you don't want to be charged") + the manage-subscription URL if you saved one
- Alarm: 24-hour-before reminder via the iCalendar
VALARMblock (TRIGGER:-P1D) - Location: The subscription URL, so on iPhone, tapping the location opens straight to the cancellation page
The end result: a calendar event that doesn't need explanation. "I see this. I know what to do. I have time to do it."
Browser (everything happens here)
↓ User adds subscription via form OR Web Share Target
Closure-based store
↓ createSubscriptionStore() factory holds private _subs array
↓ Public API: add, update, remove, getAll, getById, onChange
↓ All changes persist to localStorage automatically
Render layer
↓ Subscribe to store changes, rebuild dashboard + cards on emit
↓ textContent for every user-supplied value (XSS-safe)
Countdown ticker
↓ createCountdownTicker() runs every 60 seconds
↓ Recomputes days/hours/minutes from end-timestamps
↓ Adds .is-urgent class to cards under 24 hours
Calendar export
↓ User clicks 📅 → modal opens with three choice buttons
↓ buildReminderDetails(sub) computes title, dates, description
↓ Three exporters: buildIcsContent, buildGoogleCalendarUrl, buildOutlookUrl
↓ User picks one → file downloads OR new tab opens
The whole app is three factory functions wired together by an init() function that handles DOM events. State stays private, the UI subscribes to changes, and persistence is automatic.
- Bank/Card Integration: A Plaid integration to detect new subscription charges automatically — capture the cost and merchant without the user typing.
- Email Forwarding: A unique "subscriptions@coyote.app" address users could forward signup confirmations to; backend parses the receipt and creates a card.
- Family Sharing: Optional shared dashboard for couples or households — "Our trials" not just "My trials."
- Subscription Cost Drift Detection: Notify when a recurring charge changes price (Netflix raises monthly fee), not just when a trial expires.
- Cancellation Concierge: One-click "cancel for me" assistance for the most common services.
- Browser Extension: A capture extension that auto-detects "Free trial — your card will be charged $X.XX after 7 days" language on signup pages and offers to add to Coyote.
If you want to run a local copy for development:
# Clone the repo
git clone <your-repo-url>
cd coyote
# Serve as a static site — any of these work:
python3 -m http.server 8000
# OR with VS Code's Live Server extension
# OR with any static file server you prefer
# Open http://localhost:8000 in your browserThere's no build step, no npm install, no backend to run. Coyote is plain HTML, CSS, and JavaScript — open the folder, serve it, you're running it. PWA features (service worker, install button, Web Share Target) require HTTPS or localhost, both of which the above setup satisfies.
Coyote is what I built during Phase I of Thinking with AI — a single, focused tool that solves one real problem (the surprise trial charge) using only the browser, with no backend, no API key, no account, and a calendar-export system reliable enough to live across every device the user owns.
Easiest method — use the address bar instead of the bookmarks manager:
- Click the three-dot menu (top-right of Chrome, looks like ⋮) → Bookmarks and lists → Bookmark manager
- Once inside the bookmark manager, click the three-dot menu in the top-right corner of the bookmark manager itself (NOT the Chrome menu — the one inside the manager page) → Add new bookmark
OR even easier:
- Open any random page in a tab
- Click the ★ star icon in Chrome's address bar to bookmark that page
- In the dialog that pops up, click Edit
- Now you have a bookmark you can edit. Replace the URL with the bookmarklet code (paste it)
- Rename to "Capture to Coyote"
- Save
Or the fastest method of all — use Chrome's hidden keyboard shortcut to add a bookmark:
- Make sure you're on any tab (not the bookmarks manager page)
- Press Cmd+D (Mac) or Ctrl+D (Windows) — this opens the "Add bookmark" dialog
- Click Edit more... at the bottom of that dialog
- Replace the URL with the bookmarklet code (paste)
- Set the name to "Capture to Coyote"
- Save
- You're on auth.hulu.com/web/create-account/...
- Click the Capture to Coyote bookmark in your bookmarks bar
- A new Chrome tab opens. URL contains ?prefill=1&url=...&name=...
- Coyote loads, and immediately the Add Subscription modal pops up, with "Hulu" already typed in the Service Name field and the Hulu URL already filled in the URL field
- You only need to add the monthly cost ($14.99 or whatever) and trial end date, then hit Save
- The card appears on your dashboard, countdown ticking
Mac desktop:
- Visit Coyote in Chrome or Edge
- Click the ⬇ Install button at the top right
- Coyote becomes a desktop app
- Now go sign up for any free trial — when you finish, on the confirmation page click the URL bar's Share button (or use Mac's system Share menu)
- Coyote should appear as a destination
- Pick it → Coyote opens with the URL pre-filled in the Add form
iPhone:
- Visit Coyote in Safari
- Tap Share → Add to Home Screen
- Now go sign up for any trial in Safari
- On the confirmation page, tap Share
- Coyote should appear in the share sheet
- Tap it → Coyote opens with URL+title pre-filled
⭐ Love this project? Give it a star and explore the other deployed projects in this portfolio.