Bring every guest's photos home
Every photo from your event, full quality, in your own Google Drive — without asking two hundred people to install anything.
The photographs from a wedding are spread across two hundred phones and mostly stay there. The few that reach the host arrive over WhatsApp, recompressed to a fraction of their original quality, or buried in a message thread nobody scrolls back through. Everyone who was there has the pictures. The person whose day it was does not.
The host shares one link, or prints the QR code for the venue. A guest opens it, picks their photos and uploads — no app to install, no account to create. The files go straight from the guest's browser into the host's own Google Drive at full resolution, organised by event and sub-event.
Participation is the product, not storage. Every step between a guest and the upload button costs you a share of the photographs, and the drop-off is unforgiving: an app install loses most of your guests and an account signup loses most of the rest. So the guest path had to work for someone standing at a reception, one-handed, on venue wifi, with no prior relationship to the product.
Quality is the promise. If the files arrive recompressed then the product has no reason to exist, because WhatsApp already does that for free. That ruled out anything that re-encodes in transit and put real weight on how large files move from a phone to somewhere durable.
The last decision was where the photographs live. They go to the host's own Google Drive rather than to Nenpsy's storage. Running cost stays flat as events grow, the host keeps everything whether or not they keep using the product, and Nenpsy never becomes the custodian of several hundred people's private photographs — a promise worth making and a liability worth not having.
What I underestimated was the phone. Most of the hard engineering here is not the upload; it is everything the browser does to you while the upload is running.
Files go from the guest's browser straight to Google Drive
The server mints a resumable upload session and hands it back; the bytes never pass through it. That keeps full-resolution originals intact, means a serverless function is never holding a 40 MB video, and puts the photographs in the host's Drive from the first byte rather than being copied there later.
Trade-off
Uploading against the host's Drive quota means an anonymous guest can spend a resource that belongs to someone else, so the endpoint has to be defended more carefully than a normal upload route.
A guest opens the event link or scans the QR code printed for the venue, picks photos, and the browser writes them to IndexedDB before a single request goes out. For each file the client calls an init endpoint, which checks the rate limit, resolves the album and the caller's role, confirms the event is still accepting uploads, and asks Google for a resumable upload session scoped to the host's Drive folder. That session URL comes back to the browser, which PUTs the file directly to Google — the application server never handles the bytes.
When the transfer finishes the client calls a completion endpoint with the resulting Drive file id, which records the memory against the event, reads back the image dimensions, sets sharing, and revalidates the affected pages. Because the two halves are separate, a tab that dies mid-batch can be resumed from IndexedDB, and an upload authorised before a code session expired still completes.
There are two kinds of album. An EVENT has a host, managers who can be invited to help run it, viewers with read access, and guests who arrive through a shared link — each with its own invite token and its own permissions. A PERSONAL_SPACE is the anonymous mode: no roles at all, entry through a rotating code the owner can rotate or disable, and photos only.
Keeping them as separate kinds rather than one permission matrix is deliberate. The checks that matter for an event album — is this person a manager, has this viewer been invited — have no meaning for an anonymous visitor holding a code, and collapsing the two would have meant every guard carrying an exception for the other case.