Frameworks & Plattformen

Minaya besteht aus einem einzigen Script-Tag und funktioniert daher auf jeder Website ohne Framework-Integration. Im Folgenden finden Sie die Besonderheiten je Plattform — wo das Snippet eingefügt wird und worauf Sie achten sollten.

Welcher Ansatz für Sie zutrifft

PlattformAnsatz
HTML / beliebige WebsiteLädt widget.js
Next.jsLädt widget.js
React (Vite / CRA)Lädt widget.js
AngularLädt widget.js
WordPressLädt widget.js
ShopifyLädt widget.js
React NativeWebView
Android (Kotlin)WebView oder REST-API
iOS (Swift)WebView oder REST-API

Alle Browser-Plattformen laden dieselbe widget.js. Native mobile Apps haben kein DOM, daher hosten diese Plattformen das Widget entweder in einer WebView oder rufen die öffentliche REST-API auf und rendern die Unterhaltung in ihrer eigenen Benutzeroberfläche.

HTML / beliebige Website

Ein Script-Tag vor dem schließenden body-Tag.

Snippet einfügen

Fügen Sie dies unmittelbar vor </body> auf jeder Seite ein, auf der das Widget angezeigt werden soll.

<script
  src="https://widget.minaya.ai/widget.js"
  data-site-key="your-site-key"
  data-api-url="https://api.minaya.ai"
  async
></script>

Next.js

Verwenden Sie next/script, damit das Widget geladen wird, nachdem die Seite interaktiv ist.

Zum Root-Layout hinzufügen

App Router — app/layout.tsx. Die Strategie lazyOnload hält das Widget aus dem kritischen Ladepfad heraus.

import Script from "next/script";

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body>
        {children}
        <Script
          src="https://widget.minaya.ai/widget.js"
          data-site-key="your-site-key"
          data-api-url="https://api.minaya.ai"
          strategy="lazyOnload"
        />
      </body>
    </html>
  );
}

Alternative für den Pages Router

Wenn Sie pages/_app.tsx verwenden, rendern Sie dort stattdessen dieselbe <Script>-Komponente.

Hinweis. Platzieren Sie das Script nicht in next/head — Next entfernt Script-Tags daraus. Verwenden Sie next/script.

React (Vite / CRA)

Fügen Sie das Tag zu index.html hinzu oder binden Sie es über einen Hook ein.

Am einfachsten — index.html

Fügen Sie das Snippet vor </body> in Ihrer index.html ein. Weiter ist nichts zu tun.

<script
  src="https://widget.minaya.ai/widget.js"
  data-site-key="your-site-key"
  data-api-url="https://api.minaya.ai"
  async
></script>

Oder über eine Komponente einbinden

Nützlich, wenn das Widget nur auf bestimmten Routen erscheinen soll. Das Cleanup entfernt das Tag beim Unmount.

import { useEffect } from "react";

function MinayaWidget() {
  useEffect(() => {
    const script = document.createElement("script");
    script.src = "https://widget.minaya.ai/widget.js";
    script.dataset.siteKey = "your-site-key";
    script.dataset.apiUrl = "https://api.minaya.ai";
    script.async = true;
    document.body.appendChild(script);

    return () => {
      script.remove();
    };
  }, []);

  return null;
}

Angular

Fügen Sie das Tag zu index.html hinzu oder binden Sie es über eine Komponente ein.

Am einfachsten — src/index.html

Fügen Sie das Snippet vor </body> ein.

<script
  src="https://widget.minaya.ai/widget.js"
  data-site-key="your-site-key"
  data-api-url="https://api.minaya.ai"
  async
></script>

Oder über eine Komponente laden

Renderer2 hält die DOM-Zugriffe kompatibel mit serverseitigem Rendering.

import { Component, OnInit, Renderer2, Inject } from "@angular/core";
import { DOCUMENT } from "@angular/common";

@Component({ selector: "app-minaya", template: "" })
export class MinayaComponent implements OnInit {
  constructor(
    private renderer: Renderer2,
    @Inject(DOCUMENT) private document: Document,
  ) {}

  ngOnInit(): void {
    const script = this.renderer.createElement("script");
    script.src = "https://widget.minaya.ai/widget.js";
    script.setAttribute("data-site-key", "your-site-key");
    script.setAttribute("data-api-url", "https://api.minaya.ai");
    script.async = true;
    this.renderer.appendChild(this.document.body, script);
  }
}

WordPress

Fügen Sie es in den Theme-Footer ein oder verwenden Sie ein Plugin für Header-/Footer-Scripts.

Option A — ein Plugin (empfohlen)

Installieren Sie WPCode oder Insert Headers and Footers, öffnen Sie dessen Einstellungen und fügen Sie das Snippet in das Footer-Feld ein. Das übersteht auch Theme-Updates.

<script
  src="https://widget.minaya.ai/widget.js"
  data-site-key="your-site-key"
  data-api-url="https://api.minaya.ai"
  async
></script>

Option B — das Theme bearbeiten

Design → Theme-Datei-Editor → footer.php. Fügen Sie das Snippet unmittelbar vor </body> ein. Verwenden Sie ein Child-Theme, sonst überschreibt ein Update die Änderung.

Überprüfen

Öffnen Sie Ihre Website in einem privaten Fenster. Der Launcher erscheint innerhalb von ein bis zwei Sekunden unten rechts.

Hinweis. Funktioniert mit Elementor, Divi und anderen Page-Buildern — es handelt sich um reines JavaScript, keine Plugin-Integration.

Shopify

Fügen Sie es in theme.liquid vor dem schließenden body-Tag ein.

Theme-Editor öffnen

Online-Shop → Themes → ... → Code bearbeiten.

theme.liquid bearbeiten

Öffnen Sie unter Layout die Datei theme.liquid und fügen Sie das Snippet unmittelbar vor </body> ein. Speichern.

<script
  src="https://widget.minaya.ai/widget.js"
  data-site-key="your-site-key"
  data-api-url="https://api.minaya.ai"
  async
></script>

Ihre Shop-Domain zulassen

Fügen Sie in Minaya sowohl Ihre myshopify.com-Domain als auch Ihre eigene Domain unter Erlaubte Ursprünge hinzu.

Hinweis. Shopify blockiert Skripte von Drittanbietern auf Checkout-Seiten, sofern Sie nicht Shopify Plus nutzen — das Widget erscheint daher während des Checkouts nicht.

React Native

React Native besitzt kein DOM, daher hosten Sie das Widget in einer WebView.

react-native-webview installieren

npm install react-native-webview, anschließend für iOS pod install ausführen.

npm install react-native-webview

Das Widget in einer WebView rendern

Das Widget öffnet sich automatisch, damit der Besucher innerhalb der WebView keinen Launcher suchen muss.

import { WebView } from "react-native-webview";

const html = `<!doctype html>
<html>
  <head><meta name="viewport" content="width=device-width, initial-scale=1" /></head>
  <body>
    <script
      src="https://widget.minaya.ai/widget.js"
      data-site-key="your-site-key"
      data-api-url="https://api.minaya.ai"
    ></script>
  </body>
</html>`;

function SupportChat() {
  return (
    <WebView
      originWhitelist={["*"]}
      source={{ html, baseUrl: "https://api.minaya.ai" }}
    />
  );
}

„Automatisch öffnen" aktivieren

Aktivieren Sie in den Widget-Einstellungen zum Erscheinungsbild die Option Automatisch öffnen, damit das Panel innerhalb der WebView bereits geöffnet ist.

Hinweis. baseUrl muss gesetzt sein, sonst ist der Anfrage-Ursprung null und die Site-Key-Prüfung lehnt ihn ab. Fügen Sie diesen Ursprung zu Erlaubte Ursprünge hinzu.

Android (Kotlin)

Hosten Sie das Widget entweder in einer WebView oder rufen Sie die REST-API auf und verwenden Sie Ihre eigene Benutzeroberfläche.

Option A — WebView

Der schnellste Weg. JavaScript muss aktiviert sein, sonst läuft das Widget nicht.

val webView = findViewById<WebView>(R.id.webView)
webView.settings.javaScriptEnabled = true

val html = """
  <!doctype html>
  <html>
    <head><meta name="viewport" content="width=device-width, initial-scale=1" /></head>
    <body>
      <script src="https://widget.minaya.ai/widget.js"
              data-site-key="your-site-key"
              data-api-url="https://api.minaya.ai"></script>
    </body>
  </html>
""".trimIndent()

webView.loadDataWithBaseURL("https://api.minaya.ai", html, "text/html", "UTF-8", null)

Option B — native Benutzeroberfläche über die REST-API

Erstellen Sie den Chat in Compose oder Views und rufen Sie die API direkt auf. Behalten Sie die zurückgegebene sessionId und senden Sie sie zurück, um eine Unterhaltung fortzusetzen.

data class ChatRequest(val message: String, val sessionId: String? = null)
data class ChatResponse(val sessionId: String, val reply: String)



// Retrofit setup
val api = Retrofit.Builder()
    .baseUrl("https://api.minaya.ai/")
    .addConverterFactory(GsonConverterFactory.create())
    .build()
    .create(MinayaApi::class.java)

val response = api.chat("your-site-key", ChatRequest("What are your hours?"))

Hinweis. Ihr Site-Key liegt innerhalb des App-Binaries und sollte daher als öffentlich betrachtet werden. Erlaubte Ursprünge schützen nativen Datenverkehr nicht — verlassen Sie sich auf die planabhängigen Nachrichtenlimits.

iOS (Swift)

Hosten Sie das Widget entweder in einer WKWebView oder rufen Sie die REST-API auf und verwenden Sie Ihre eigene Benutzeroberfläche.

Option A — WKWebView

Lädt dasselbe Widget, das auch Ihre Website verwendet.

import WebKit

let webView = WKWebView(frame: view.bounds)
view.addSubview(webView)

let html = """
<!doctype html>
<html>
  <head><meta name="viewport" content="width=device-width, initial-scale=1" /></head>
  <body>
    <script src="https://widget.minaya.ai/widget.js"
            data-site-key="your-site-key"
            data-api-url="https://api.minaya.ai"></script>
  </body>
</html>
"""

webView.loadHTMLString(html, baseURL: URL(string: "https://api.minaya.ai"))

Option B — native Benutzeroberfläche über die REST-API

Erstellen Sie den Chat in SwiftUI und rufen Sie die API direkt auf. Speichern Sie sessionId, um die Unterhaltung über mehrere Nachrichten hinweg fortzusetzen.

struct ChatResponse: Decodable {
    let sessionId: String
    let reply: String
}

func sendMessage(_ text: String, sessionId: String?) async throws -> ChatResponse {
    var request = URLRequest(url: URL(string: "https://api.minaya.ai/public/chat")!)
    request.httpMethod = "POST"
    request.setValue("application/json", forHTTPHeaderField: "Content-Type")
    request.setValue("your-site-key", forHTTPHeaderField: "X-Site-Key")

    var body: [String: Any] = ["message": text]
    if let sessionId { body["sessionId"] = sessionId }
    request.httpBody = try JSONSerialization.data(withJSONObject: body)

    let (data, _) = try await URLSession.shared.data(for: request)
    return try JSONDecoder().decode(ChatResponse.self, from: data)
}

Hinweis. Ihr Site-Key liegt innerhalb des App-Binaries und sollte daher als öffentlich betrachtet werden. Erlaubte Ursprünge schützen nativen Datenverkehr nicht — verlassen Sie sich auf die planabhängigen Nachrichtenlimits.

Fehlerbehebung

Das Widget erscheint nicht

Öffnen Sie die Browser-Konsole. Ein fehlendes data-site-key oder data-api-url protokolliert einen expliziten Fehler. Ist die Konsole sauber, prüfen Sie, ob sich das Script-Tag innerhalb von <body> befindet und nicht durch eine Content-Security-Policy blockiert wird.

403 bei jeder Anfrage

Der anfragende Ursprung steht nicht auf der Allowlist des Widgets. Fügen Sie den exakten Ursprung — einschließlich Schema — unter Erlaubte Ursprünge hinzu. Eine WebView ohne baseUrl sendet einen null-Ursprung, der niemals übereinstimmt.

Zwei Widgets auf der Seite

Das Script ist zweimal eingebunden. Minaya ignoriert die zweite Kopie, sodass Sie nur einen Launcher sehen sollten; sehen Sie zwei, handelt es sich bei einem davon um ein anderes Chat-Produkt.