Share-URL-Schema: wie der ganze Wunschlisten-Inhalt in den Link passt

Wenn eine Wunschliste per Link geteilt wird ohne dass ein Server beteiligt ist, muss der komplette Inhalt in der URL stecken. Dieser Ratgeber erklärt wie der Browser das schafft und wo die praktischen Grenzen liegen.

Tobias Hesse
Tobias HesseMaker- & Tech-Redaktion · QR-Code, Share-URLs, Wunschzettel-Historie
Veröffentlicht am ·Zuletzt geprüft am

Auf den ersten Blick wirkt es magisch: eine Wunschliste mit fünfzehn Einträgen, Reservierungs-Status und Notizen, alles in einem Link, ohne dass irgendwo ein Server steht. Hinter der Magie steckt eine Folge von drei Encoding-Schritten, die zusammen den Listen-Inhalt in eine URL-sichere Form bringen. Wer das Pattern einmal verstanden hat, kann es auch für eigene Mini-Tools nachbauen.

Der grobe Ablauf

Vom JavaScript-Objekt zur fertigen URL passieren vier Schritte:

  1. JSON-Serialisierung. Das Wunschlisten-Objekt wird mit JSON.stringify in einen String umgewandelt. Aus { ownerName: "Mia", items: [...] } wird '{"ownerName":"Mia","items":[...]}'.
  2. Unicode-sichere Codierung. Der String wird über encodeURIComponent in seine UTF-8-Bytes übersetzt, wichtig für Umlaute, Emojis und nicht-lateinische Schriften.
  3. Base64-Codierung. Die Byte-Sequenz wird über btoa in Base64 verwandelt.
  4. URL-safe Zeichenersatz. Die Zeichen +, / und = aus dem Standard-Base64 werden durch -, _ und Wegstreichen ersetzt, sonst kollidieren sie mit URL-Sonderbedeutungen.

Das Ergebnis wird an die URL nach #share= angehängt. Beim Oeffnen läuft die Kette in umgekehrter Reihenfolge ab und liefert das Wunschlisten-Objekt zurück.

Warum nicht einfach btoa?

Wer schon mal versucht hat btoa("Müller") im Browser auszuführen, bekommt einen Fehler: InvalidCharacterError. Die Standard-Funktion btoa arbeitet auf einzelnen ASCII-Bytes und versteht Unicode-Codepoints jenseits von 0xFF nicht.

Die üblicher Workaround in einem Satz:

btoa(unescape(encodeURIComponent(input)))

Der encodeURIComponent-Schritt wandelt Unicode-Zeichen in percent-encoded ASCII-Bytes um (MüllerM%C3%BCller). unescape macht daraus echte Bytes (M plus zwei Latin-1-Bytes 0xC3 und 0xBC), die btoa dann fehlerfrei codieren kann.

Beim Decodieren läuft es umgekehrt: decodeURIComponent(escape(atob(input))). Beide Funktionen escape und unescape sind formell deprecated, funktionieren aber in jedem modernen Browser und sind für diesen sehr spezifischen Use-Case der schlankste Weg.

JSON.stringify {"name":"Mia"}
<rect class="box" x="160" y="40" width="120" height="60" rx="8"/>
<text class="head" x="220" y="65">encodeURI</text>
<text class="label" x="220" y="85">%7B%22name%22...</text>

<rect class="box" x="300" y="40" width="120" height="60" rx="8"/>
<text class="head" x="360" y="65">btoa</text>
<text class="label" x="360" y="85">JTdCJTIybmFtZQ==</text>

<rect class="box" x="440" y="40" width="140" height="60" rx="8"/>
<text class="head" x="510" y="65">url-safe</text>
<text class="label" x="510" y="85">JTdCJTIybmFtZQ</text>

<rect class="box" x="160" y="140" width="280" height="60" rx="8"/>
<text class="head" x="300" y="165">finale URL</text>
<text class="label" x="300" y="185">.../wunschliste/#share=JTdCJTIybmFtZQ</text>

<path class="arrow" d="M 140 70 L 160 70"/>
<path class="arrow" d="M 280 70 L 300 70"/>
<path class="arrow" d="M 420 70 L 440 70"/>
<path class="arrow" d="M 510 100 L 510 130 L 440 170"/>
Vier Encoding-Schritte vom Wunschlisten-Objekt zur fertigen URL. Beim Oeffnen läuft die Kette in umgekehrter Reihenfolge ab.

Warum Hash und nicht Query

Im URL-Format gibt es zwei Wege Daten an einen Pfad anzuhängen: nach dem Fragezeichen (?key=value) oder nach dem Doppelkreuz (#hash=value). Beide sehen ähnlich aus, sind aber grundlegend verschieden.

Der Query-Teil hinter ? wird beim HTTP-Request an den Server geschickt. Wenn die Wunschliste im Query stünde, würde der komplette Inhalt in Server-Logs landen, auch wenn der Server selbst gar nichts damit tut.

Der Hash-Teil hinter # bleibt im Browser. HTTP-Spezifikation: der Browser entfernt den Hash vor dem Versenden des Requests. Damit kommt der Wunschlisten-Inhalt nie am Server an, auch nicht in Access-Logs.

Für eine “client-only, kein Server”-Architektur ist das ideal. Der Hash wird durch JavaScript ausgelesen (window.location.hash) und dort weiterverarbeitet.

URL-Länge in der Praxis

Webserver wie Apache und nginx limitieren standardmässig die Request-URL auf 8 KB. Da der Hash aber nicht im Request landet, gelten diese Limits hier nicht, nur die Browser-eigenen Limits sind relevant. Stand heute (2026):

  • Chrome / Edge: ca. 32 KB
  • Firefox: ca. 1 MB
  • Safari: ca. 80 KB

Praktisch reicht das für Wunschlisten weit hinaus. Eine durchschnittliche Liste mit zehn Einträgen hat als Hash ca. 800–1500 Zeichen. Selbst extreme Listen mit 100 Einträgen und langen Notizen bleiben unter 30 KB.

Auf weihnachtswunschliste-online.de gibt es eine Soft-Warning ab 40.000 Zeichen, nicht weil der Browser dann scheitert, sondern weil so lange URLs in Messenger-Apps oft umgebrochen oder verkürzt werden und das Hash-Schema bricht wenn unterwegs Zeichen verloren gehen.

Vergleich zu serverseitiger Speicherung

Eine serverseitige Lösung würde die Wunschliste in einer Datenbank speichern und nur eine kurze ID im Link mitschicken (/share/abc123). Vorteile: kurze URLs, leichte Aktualisierung von zentraler Stelle. Nachteile: Server-Kosten, Daten-Privacy, Anmeldung oder zumindest Rate-Limiting nötig, Compliance-Aufwand (DSGVO, Auftragsverarbeitung), und langfristige Vorhaltung der Daten (“wer löscht alte Listen?”).

Für eine saisonale Anwendung wie eine Weihnachts-Wunschliste ist das URL-Hash-Schema klar bequemer. Niemand muss sich um Server-Wartung kümmern, niemand verwaltet Account-Daten, und nach Weihnachten verschwinden die Links einfach wieder ohne Daten-Reste.

Wann das Schema an Grenzen kommt

Bilder oder Anhänge. Ein QR-Code-Foto oder eine PDF in der Wunschliste, das würde die URL sprengen. Für solche Fälle wäre ein Server unausweichlich.

Echtzeit-Synchronisation. Wenn mehrere Personen gleichzeitig dieselbe Liste editieren wollen, klappt das Hash-Schema nicht. Es bietet nur asynchrones Teilen, wer den neueren Link hat, hat den aktülleren Stand.

Verlorene Links. Wenn alle Empfänger den Link verlieren, ist die Information weg. Es gibt kein zentrales Backup.

Worauf es wirklich ankommt

Das URL-Hash-Schema ist ein eleganter Trick für kleine, transiente Daten-Strukturen die zwischen Geräten und Personen geteilt werden sollen, ohne dass ein Server nötig ist. Die Kette aus JSON-Serialisierung, Unicode-sicherer Codierung, Base64 und URL-safe-Zeichenersatz ist robust und funktioniert in jedem modernen Browser. Wer das Pattern für eigene Tools nachbauen will, sollte vor allem auf die Unicode-Behandlung achten, sonst kollabiert das ganze System sobald jemand Müller heißt.

Häufige Fragen

Wie lang darf eine URL eigentlich sein?

Es gibt keinen festen Standard. Praktisch akzeptieren alle modernen Browser URLs bis ca. 32 KB. Webserver-Software ist oft strenger, Apache und nginx-Defaults liegen bei 8 KB. Da das Tool aber keinen Server für den Hash-Teil braucht, gelten nur die Browser-Grenzen.

Was ist der Unterschied zwischen ? und # in der URL?

Der Query-Teil hinter ? wird beim HTTP-Request an den Server geschickt. Der Hash-Teil hinter # bleibt im Browser und wird nicht übertragen. Für eine vertrauliche Wunschliste ist der Hash deshalb sicherer, der Inhalt landet nicht in Server-Logs.

Warum nicht localStorage statt URL-Hash?

localStorage ist geräte-gebunden. Wer den Link von Smartphone auf Tablet überträgt, kann localStorage nicht mitschicken. Der URL-Hash ist das einzige Vehikel das beide Geräte erreichen können ohne zentralen Server.

Was passiert mit dem Hash bei Bookmarks und Browser-History?

Beides funktioniert. Browser speichern den Hash als Teil der URL, wer also einen Wunschlisten-Link als Lesezeichen ablegt, hat den kompletten Wunschlisten-Inhalt im Lesezeichen. Vorsicht in Browsern mit geteiltem History (z.B. wenn ein Familien-Computer mehrere Nutzer-Profile teilt).

Funktioniert das Schema auch mit anderen Sprachen oder Emojis?

Ja. Die Encoding-Kette encodeURIComponent + btoa + Zeichenersatz behandelt UTF-8-Zeichen sauber. Emojis (vier Bytes pro Zeichen) funktionieren genauso wie Umlaute. Der Code wird allerdings entsprechend länger.

Anzeige

Weitere Ratgeber

Anzeige
Anzeige
Anzeige
Anzeige