Sign in

The Sign in component asks the customer to authenticate on the merchant's own Shopify Customer Accounts login page. The widget never collects or holds a customer credential. Identity is asserted by Shopify after the customer returns to the page they started on.

This requires Shopify's current Customer Accounts. Legacy (classic) customer accounts are not supported.

Example

Send this payload from Flow to render the sign-in UI and pause until the customer has signed in:

{
  "type": "signInRequested",
  "payload": {
    "platform": "shopify"
  }
}

Optional copy can be supplied in the payload. If omitted, the widget uses the lang.signIn strings:

{
  "type": "signInRequested",
  "payload": {
    "platform": "shopify",
    "title": "Sign in to continue",
    "description": "Sign in so we can find your orders and help you faster.",
    "buttonText": "Sign in"
  }
}

platform is required and must be shopify.

Configuration

The login URL is configured on the widget:

{
  "authentication": {
    "shopify": {
      "loginUrl": "/customer_authentication/login?return_to={{returnTo}}"
    }
  }
}

{{returnTo}} is replaced with the current page path and query, with dg_auth=true appended, then URL-encoded as a single return_to value. Shopify only accepts a relative path here — not a full URL.

If authentication.shopify.loginUrl is omitted, the widget uses /customer_authentication/login?return_to={{returnTo}}.

How it works

  1. Flow sends a signInRequested message and pauses.
  2. The widget renders a sign-in card and hides the chat input while that message is the latest in the conversation.
  3. If the customer clicks I don't have an account, the widget sends a signInAborted customer message and Flow can resume without a login.
  4. When the customer clicks Sign in, the current tab navigates to the merchant login page. The return path is the current page with ?dg_auth=true (or &dg_auth=true when the page already has a query string).
  5. After the customer authenticates, Shopify redirects back to that tagged path. The conversation restores from the existing session.
  6. The widget sees dg_auth=true, treats this as a login return, re-opens the widget, and removes dg_auth with history.replaceState so a refresh does not repeat the sequence.
  7. Once the conversation has restored and the websocket is connected, the widget calls /apps/dg-verify/session on the shop domain with chat_session_id and region. Shopify attaches the signed customer assertion and forwards the request to Flow.
  8. Flow verifies the signature and resumes with either signInVerified or signInVerificationFailed.

No credentials pass through the widget. The browser only carries Shopify's signed assertion, and only the returning tab makes the proxy request, so other tabs on the same conversation stay in sync via the existing session and websocket.

signInVerified

When Flow has verified the signed assertion it sends:

{
  "from": "customer",
  "content": {
    "type": "signInVerified",
    "payload": {
      "platform": "shopify"
    }
  }
}

The widget renders this as a system message using lang.signIn.verifiedMessage (default: Signed in successfully).

signInVerificationFailed

When verification fails, Flow sends:

{
  "from": "customer",
  "content": {
    "type": "signInVerificationFailed",
    "payload": {
      "platform": "shopify"
    }
  }
}

The widget renders this as a system message using lang.signIn.verificationFailedMessage (default: Sign in failed). Flow can then branch and, if needed, send another signInRequested.

signInAborted

The sign-in card also includes a secondary I don't have an account button. When the customer clicks it, the widget sends:

{
  "from": "customer",
  "content": {
    "type": "signInAborted",
    "payload": {
      "platform": "shopify"
    }
  }
}

Flow can then resume without waiting for a login. The widget renders this as a system message using lang.signIn.abortedMessage (default: Sign in skipped). The button label uses lang.signIn.abortedButtonText (default: I don't have an account).


Did this page help you?