A self-hosted, single-file web app for cat sitting client intake and visit management. Built for use alongside Meowtel, it streamlines the meet-and-greet process, tracks per-visit tasks, and gives clients a clean way to submit their care preferences before a booking begins.
Live app: brandonml.github.io/meowtel-client-questionaire
The app operates in two modes depending on how it's accessed:
Sitter (admin) view — the default experience when you open the URL directly. Used to:
- Fill in reservation details for a new client
- Save the record to Google Sheets
- Generate a pre-filled client link and send it to the client
- Load and review previous client records pulled live from Google Sheets
- Plan visits with the Visit Planner (date ranges, time windows, durations, and per-task frequencies)
- Track task completion per visit during the reservation
- Print a cat care summary for any loaded client
Client view — activated when the URL includes a ?client= parameter (generated by the sitter). Used by the client to:
- See their pre-filled reservation details (read-only)
- Answer care questions across 9 topic sections, pre-populated with any answers the sitter has already entered
- Submit their answers directly to Google Sheets
End-of-reservation summary view — shown automatically to the client when their link is opened after the reservation end date. Displays a chronological day-by-day summary of all visits, tasks completed, and tasks skipped. No sitter UI is shown.
The entire application is a single HTML file (index.html) with no build step, no framework, and no backend. It is deployed via GitHub Pages.
Data is persisted to a Google Sheet via a Google Apps Script web app (apps-script.js). The HTML file makes POST requests to the Apps Script endpoint to save records and GET requests to fetch the client list.
- Sitter fills in the client's reservation details (name, dates, address, cats, reservation number)
- Sitter answers any intake questions they already know (e.g. after the meet & greet)
- Sitter clicks Save & Get Link — this saves the record to Sheets and generates a shareable URL
- The URL encodes the reservation details as a base64 parameter:
?client=<encoded> - Sitter sends the link to the client
- Client opens the link — any answers already saved in Sheets are automatically fetched and pre-filled. The client fills in any remaining questions and clicks Submit My Answers
- Responses are saved to the same Sheets row (matched by reservation number, or by name if no res# exists)
- Sitter opens Saved Clients to view the completed record
The Visit Planner is a sitter-only panel that appears once a client's first and last name are entered. It is hidden in client mode.
- Visit groups: Define one or more date ranges, each with a visits-per-day count, time window (morning / midday / evening / no preference), duration (20 / 45 / 60 min), and a default task list
- Task frequency: Each task can be set to run every visit, odd-numbered visits only, or even-numbered visits only (for tasks like litter scooping on alternating days)
- Smart task suggestions: Tasks are pre-suggested based on the client's form answers (e.g. "Give medication" auto-suggests if the cat has medical conditions)
- Per-visit overrides: Clicking any visit tile expands it in-place, allowing tasks to be added, removed, or checked off individually without affecting other visits
- Checklist view: A full per-visit checklist view lets you add tasks from the global list or enter custom one-off tasks
- Persistence: Visit plans are saved to
localStoragekeyed by reservation number and also persisted to Sheets as part of theVisit Schedulecolumn when saved - Restoring from Sheets: When a client record is loaded from Sheets, their full visit plan (groups + per-visit overrides) is restored from the
Visit Schedulecolumn
When a client opens their link after the reservation end date and a visit plan exists in the link payload, they see a summary view instead of the intake form. This shows:
- A thank-you banner with the client's name
- Reservation details (dates, cats, address)
- A chronological list of all visit days with time window, duration, completion status, and per-task results (done vs. skipped)
- Google Sheets is the sole persistent store. All records are written and read from there.
localStorageis used for two things: the active visit plan for the current session (keyed by reservation number), and a submission flag to prevent duplicate client submissions from the same device.
The Apps Script (apps-script.js) handles two request types:
| Method | Action |
|---|---|
POST |
Upserts a client record. Matches existing rows by Reservation #; inserts a new row if no match is found. Includes a Visit Schedule column that stores visit groups and per-day task overrides as JSON. |
GET ?action=list |
Returns all sheet rows and headers as JSON, used to populate the Saved Clients panel and to fetch answers for the client link view. |
The sheet auto-creates a styled header row on first write. Subsequent writes upsert by matching column 2 (Reservation #). The Visit Schedule column is added automatically to existing sheets on first use.
The questionnaire covers 9 topic areas:
- Access to the Home
- Feeding
- Litter Box
- Cat Behavior & Personality
- Health & Emergencies
- Photos & Updates
- House Rules
- Supplies
- End of Booking
Questions use a mix of input types: radio pill buttons, checkboxes, dropdowns, and text areas. Several questions include collapsible "Add details" fields for optional notes. Conditional visibility is used for:
- "Where should I leave the key after the final visit?" — shown only when access method is Key or Other
- "Any medications required?" and "How is medication given?" — shown only when medical conditions are marked Yes
The app is designed for GitHub Pages. Fork or clone this repo and enable Pages from the main branch root. No build step required.
- Open script.google.com and create a new project
- Paste the contents of
apps-script.jsinto the editor - Click Deploy → New deployment
- Type: Web app
- Execute as: Me
- Who has access: Anyone
- Copy the deployment URL
In index.html, update two constants near the bottom of the <script> block:
// Your Apps Script deployment URL
const SHEETS_URL = 'https://script.google.com/macros/s/YOUR_DEPLOYMENT_ID/exec';
// The public URL of your deployed app
const BASE_URL = 'https://your-username.github.io/your-repo-name/';When you redeploy changes to the Apps Script, you must create a new version — the endpoint URL stays the same, but Apps Script only serves the latest published version.
Go to Deploy → Manage deployments → Edit → change "Version" to a new version → Deploy.
- The Apps Script endpoint is publicly accessible (required for client form submissions). It is write-only by design — the
POSThandler can only append/update rows in your specific sheet. - The
GET ?action=listendpoint returns your full client list as JSON to anyone with the URL. This is acceptable given the low-sensitivity nature of cat care data, but worth being aware of if you store any personally identifiable information beyond names and addresses. - The
?client=URL parameter is base64-encoded, not encrypted. Anyone with the link can read the encoded reservation details. Links should be sent only to the intended client. - If you want to restrict access in the future, consider adding a shared secret token validated by the Apps Script.
| File | Purpose |
|---|---|
index.html |
The entire application — HTML, CSS, and JS in a single file |
js/apps-script.js |
Google Apps Script source for the Sheets integration backend |
README.md |
This file |
- Vanilla HTML/CSS/JS — no framework, no build tooling
- Poppins + DM Sans via Google Fonts
- Google Apps Script (web app deployment) for persistence
- GitHub Pages for hosting
This project was built for personal use as a Meowtel cat sitter. It is not affiliated with or endorsed by Meowtel. If you're a cat sitter and find it useful, feel free to fork it and adapt it for your own workflow — just update SHEETS_URL and BASE_URL with your own values.