# Code in der App

Fast alles in einer Mini-App wird ohne Code gebaut. Reichen die fertigen Elemente und Blöcke nicht aus, können Sie eigenen Code an drei Stellen hinzufügen:

| Wo | Wann er ausgeführt wird | Wofür |
|---|---|---|
| Block „JavaScript“ | Wenn das Szenario den Block erreicht | Eine Aktion beim Tippen: Text kopieren, einen Link öffnen, einen Wert berechnen, mit der Bridge des Messengers sprechen |
| App-Code | Einmal beim Start, vor dem ersten Bildschirm, und danach bei Ereignissen | Analytics-Zähler, eigene Stile, externe Widgets |
| „HTML-Code“ — ein Element oder ein ganzer Bildschirm | Solange der Bildschirm geöffnet ist | Eigenes Layout, ein Rechner, ein Widget eines fremden Dienstes |

Der Code läuft auf dem Gerät der Person. Wer sich mit dem Browser auskennt, kann ihn deshalb sehen und fälschen, was der Code an den Server sendet. Legen Sie keine geheimen Schlüssel im Code ab und begrenzen Sie, welche Variablen und Tags der Code ändern darf — mehr dazu unten.

## Block „JavaScript“

Ein Block aus der Kategorie „Daten und Logik“. Erreicht die App den Block, führt sie den Code aus und geht über den Ausgang „Ausgeführt“ oder „Fehler“ weiter.

| Einstellung | Was sie festlegt |
|---|---|
| „Code“ | Der Rumpf einer asynchronen Funktion: Schreiben Sie mit `await` und dem Objekt `app`. Bis zu 20 000 Zeichen |
| „Zeitlimit, Sekunden“ | Von 1 bis 60, standardmäßig 10. Dauert es länger, geht das Szenario über den Ausgang „Fehler“ weiter, und der Code selbst kann im Hintergrund zu Ende laufen |
| „Ergebnisvariable“ | Was `return` zurückgegeben hat. Ein Objekt wird als JSON gespeichert |
| „Fehlervariable“ | Der Fehlertext — für den Bildschirm nach dem Ausgang „Fehler“ |
| „Was der Code ändern darf“ | Die Liste des Erlaubten — siehe unten |

![Einstellungen des Blocks „JavaScript“](https://support.watbot.org/_media/de/02-mini-apps/_images/js-block.webp?v=1791781229)

Platzhalter `{{ name }}` funktionieren im Code nicht: Lesen Sie Variablenwerte über `app.variables.get()`.

Variablen, die über `app.variables.set()` geschrieben wurden, und geänderte Tags gehen zusammen mit dem Ausgang des Blocks an den Server.

### „Was der Code ändern darf“

Der Schalter „Nur Aufgelistetes ändern“ ist bei einem neuen Block eingeschaltet. Damit nimmt der Server vom Code nur Folgendes an:

- Variablen aus der Liste „Variablen“;
- Tags aus den Listen „Tags des Bot-Kontakts“ und „Tags des App-Nutzers“ — eine leere Liste bedeutet, dass der Code diese Tags gar nicht ändert;
- die Ergebnis- und die Fehlervariable — sie sind immer erlaubt.

Alles andere verwirft der Server und schreibt in das Fehlerprotokoll „Der Block hat das vom Code Geschriebene verworfen“. Schreibt der Code Namen, die nicht in den Listen stehen, warnen die Einstellungen des Blocks davor und bieten „Zu den Listen hinzufügen“ an.

Schalten Sie die Einschränkung nur aus, wenn nichts von den Variablen und Tags abhängt: Sonst kann sich eine Person zum Beispiel das Tag VIP oder einen Rabatt verschaffen.

### Das Objekt `app`

| Aufruf | Was er tut |
|---|---|
| `app.variables.get('name')` | Wert einer Variable |
| `app.variables.set('name', value)` | Variable schreiben — geht mit dem Ausgang des Blocks an den Server |
| `app.variables.all()` | Alle Variablen als Objekt |
| `app.tags.has('vip')` / `add('vip')` / `remove('vip')` / `all()` | Tags des App-Nutzers — jeder hat sie, auch ohne Chatbot |
| `app.contact?.name` | Kontakt des Chatbots: `id`, `name`, `first_name`, `last_name`, `username`, `phone`, `email`, `address`, `source`, `created_at`, `telegram_id`, `max_id`. `null`, wenn die App nicht aus einem Bot geöffnet wurde |
| `app.contact.variables.get('name')` / `set('name', value)` | Eigene Variablen des Kontakts, getrennt von den Variablen der App. Was geschrieben wird, geht mit dem Ausgang des Blocks in den Kontakt |
| `app.contact.tags.has('vip')` / `add` / `remove` / `all()` | Tags des Bot-Kontakts |
| `app.platform` | Woher die App geöffnet wurde: `telegram`, `max`, `webchat`, `pwa` oder `browser` |
| `app.startParam` | Parameter des Startlinks (`startapp`) |
| `app.user` | `language`, `name` und `username` im Messenger |
| `app.device` | `mode` (`ios` oder `md`), `dark`, `standalone`, `width`, `height`, `userAgent` |
| `await app.toast(message)` | Kurzmeldung |
| `await app.alert(message, title)` | Meldung mit dem Button OK — wartet, bis sie geschlossen wird |
| `await app.confirm(question)` | Ja/Nein-Frage — gibt `true` oder `false` zurück |
| `app.openLink('https://…')` | Link öffnen: im Messenger über dessen Mittel, sonst in einem neuen Tab |
| `await app.copy(text)` | In die Zwischenablage kopieren |
| `await app.share({title, text, url})` | Das Teilen-Menü des Systems; ohne es wird der Link kopiert |
| `app.vibrate('success')` | Vibration: `light`, `medium`, `heavy`, `success`, `warning` oder `error` |
| `app.localStorage.setItem('key', 'value')` | Speicher des Nutzers auf dem Server — siehe unten |
| `app.storage.get('key')` / `set` / `remove` | Speicher auf dem Gerät, eigener für jede App |
| `await app.sleep(500)` | Die angegebene Zahl von Millisekunden warten |
| `app.close()` | App schließen |
| `app.telegram` | `Telegram.WebApp` direkt, außerhalb von Telegram — `null` |
| `app.max` | Die Bridge von MAX direkt, außerhalb von MAX — `null` |

Beispiel aus den Einstellungen des Blocks:

```js
// Thema und Bildschirmbreite – in Variablen
const device = app.device
app.variables.set('theme', device.dark ? 'dark' : 'light')

if (app.platform === 'telegram') {
    app.vibrate('success')
}

// Der Rückgabewert kommt in die Ergebnisvariable
return device.width
```

Fehler im Code sind in der Vorschau in der Browserkonsole sichtbar und landen im [Fehlerprotokoll](https://support.watbot.org/de/mini-apps/users) — „JavaScript-Fehler“.

## App-Code

Code für die ganze App: Er wird einmal beim Start ausgeführt, vor dem ersten Bildschirm, und hört auf Ereignisse. Sie öffnen ihn mit dem Button „App-Code“ (Symbol „</>“) in der Leiste über dem Schema. Ist Code hinterlegt, ist das Symbol eingefärbt.

Im Fenster „App-Code“:

- „Code“ — bis zu 100 000 Zeichen;
- „Variablen, die der Code schreiben darf“ — bis zu 50 Namen. Andere Variablen nimmt der Server nicht an;
- eine Übersicht der Ereignisse und ein „Beispiel“ mit dem Button „Beispiel einfügen“.

![Fenster „App-Code“](https://support.watbot.org/_media/de/02-mini-apps/_images/app-code.webp?v=1791781229)

Der Code wird in der Version gespeichert: Eine neue Version und eine Vorlage erhalten eine Kopie davon. Nach dem Speichern startet eine geöffnete Vorschau neu.

### Ereignisse

| Abonnement | Wann es auslöst |
|---|---|
| `app.on('start', ({platform, startParam}) => {})` | Die App wurde gestartet |
| `app.on('screen', ({id, name, type}) => {})` | Ein Bildschirm oder ein Fenster darüber wird angezeigt |
| `app.on('event', ({blockId, eventId}) => {})` | Tippen auf einen Button, einen Listenpunkt oder ein Element — vor dem Senden an den Server |
| `app.on('field', ({variable, value}) => {})` | Die Person hat ein Eingabefeld geändert |
| `app.on('error', ({message}) => {})` | Die App hat einen Fehler angezeigt |
| `app.on('hide', () => {})` / `app.on('show', () => {})` | Die App wurde ausgeblendet und wieder geöffnet |
| `app.on('theme', ({dark}) => {})` | Helles oder dunkles Design wurde gewechselt |
| `app.on('storage', ({key, newValue}) => {})` | Der Code eines Elements „HTML“ hat in localStorage geschrieben |

- Ein Abonnement auf `start`, `screen` und `theme` erhält sofort den aktuellen Wert — auch wenn es nach `await` abgeschlossen wurde.
- `app.on()` gibt eine Funktion zum Abbestellen zurück: `const stop = app.on(…); stop()`. Es gibt auch `app.off(name, handler)`.
- `await app.loadScript('https://…')` lädt ein externes Skript: einen Zähler, ein Widget, eine Bibliothek. Die Adresse — nur `http://` oder `https://`.

Alles andere wie beim Block „JavaScript“: `app.variables`, `app.toast`, `app.alert`, `app.openLink`, `app.storage`, `app.localStorage`, `app.telegram` und weitere. `app.contact` und `app.tags` sind hier nur lesbar: Tags zu ändern ist Aufgabe der Tag-Blöcke.

Variablen, die über `app.variables.set()` geschrieben wurden, gehen mit dem nächsten Ereignis an den Server.

Beispiel aus dem Fenster — Google-Tag:

```js
// Google-Tag einbinden
window.dataLayer = window.dataLayer || []
function gtag() { dataLayer.push(arguments) }
gtag('js', new Date())
gtag('config', 'G-XXXXXXXXXX', {send_page_view: false})
await app.loadScript('https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXXX')

// Jeder Bildschirm ist ein Seitenaufruf
app.on('screen', ({id, name}) => {
    gtag('event', 'page_view', {page_title: name, page_location: location.origin + '/screen/' + id})
})

// Tippen sind Ereignisse
app.on('event', ({eventId}) => {
    gtag('event', 'tap', {event_id: eventId})
})
```

Fehler im App-Code — beim Start und in den Handlern — sind in der Konsole sichtbar und landen im Fehlerprotokoll mit dem Grund „Fehler im App-Code“ und dem Aufrufstapel. Derselbe Fehler wird nur einmal geschrieben.

## „HTML-Code“: Element und Bildschirm

Eigenes HTML mit Skripten und Stilen gibt es in zwei Formen:

- **Element „HTML-Code“** — in der Gruppe „Widgets“, steht in einem Bereich des Bildschirms neben anderen Elementen;
- **Bildschirm „HTML-Code“** — die dritte Bildschirmart nach „Standardfenster“ und „Tabs unten“: Der ganze Bildschirm ist Ihr Code, ohne Kopfzeile und Bereiche. Ein neuer Bildschirm dieser Art erhält sofort ein Beispiel mit einem Button und den Ausgang `next`. Zu einem modalen Fenster lässt er sich nicht machen.

Der Code läuft in einem isolierten Frame: Sitzung, Daten der App und der übrige Bildschirm sind für ihn nicht erreichbar. Skripte und Stile gehören in den Code. Die Textfarbe übernimmt der Frame aus dem Design der App.

| Einstellung | Was sie festlegt |
|---|---|
| „Code“ | HTML bis zu 100 000 Zeichen |
| „Höhe“ (beim Element) | „Nach Inhalt“ — passt sich dem Code an, auch wenn er seinen Inhalt selbst ändert; „Fest“ — von 40 bis 2000 Pixel, was nicht hineinpasst, wird innerhalb gescrollt |
| „Ausgänge“ | Bis zu 20. Ein Ausgang hat einen „Schlüssel“ (lateinische Buchstaben, Ziffern, `_` und `-`) und einen „Name im Schema“. Ein Ausgang ist ein Übergang zu einem anderen Block des Schemas |
| „Variablen, die der Code schreiben darf“ | Bis zu 50 Namen. Andere nimmt der Server nicht an |

![Element „HTML-Code“: Code, Ausgänge und Variablen](https://support.watbot.org/_media/de/02-mini-apps/_images/html-element.webp?v=1791781229)

### Was der Code im Frame nutzen kann

| Aufruf | Was er tut |
|---|---|
| `app.event('next')` | Über den Ausgang mit diesem Schlüssel weitergehen |
| `app.event('next', {name: 'value'})` | Weitergehen und erlaubte Variablen schreiben |
| `app.variables.set('name', 'value')` | Eine erlaubte Variable sofort schreiben, ohne Übergang: Der Bildschirm bleibt |
| `localStorage.setItem('key', 'value')` | Speicher des Nutzers auf dem Server — siehe unten. `sessionStorage` gilt, solange der Bildschirm offen ist |
| `app.openLink('https://…')` | Einen Link im Browser öffnen. Gewöhnliche Links `<a>` öffnen sich genauso |
| `{{ name }}` | Den Wert einer Variable direkt in den Code einsetzen — als Text, maskiert |

Im Schema wird der Code nicht ausgeführt — stattdessen erscheint ein Platzhalter. Im Bildschirm-Editor zeigt der Frame das Ergebnis und startet nach einer Änderung des Codes neu.

## Speicher

| | `localStorage` auf dem Server | `app.storage` |
|---|---|---|
| Wo verfügbar | `localStorage` im Frame „HTML-Code“, `app.localStorage` im Block „JavaScript“ und im App-Code | Block „JavaScript“ und App-Code |
| Wo er liegt | Auf dem Server, beim App-Nutzer | Im Browser der Person |
| Übersteht | Neustart, Leeren des Telefons, Gerätewechsel im selben Messenger | Bis die Browserdaten gelöscht werden |
| Gemeinsam | Für alle Elemente „HTML-Code“, den App-Code und die Blöcke „JavaScript“ einer App | Eigener für jede App |
| Werte | Nur Strings, bis zu 100 000 Zeichen samt Schlüsseln | Beliebige Werte, gespeichert als JSON |

Der Speicher auf dem Server ist für jede Plattform eigen: Bei derselben Person ist er in Telegram, MAX und im Browser verschieden.

## Einschränkungen

- Der Code des Blocks „JavaScript“ hat bis zu 20 000 Zeichen, der App-Code und der HTML-Code bis zu 100 000.
- Das Zeitlimit des Blocks „JavaScript“ beträgt bis zu 60 Sekunden.
- Ins Protokoll gelangen höchstens 20 Fehler pro Minute von einem Block.
