> ## Documentation Index
> Fetch the complete documentation index at: https://developers.loyaltylion.com/llms.txt
> Use this file to discover all available pages before exploring further.

# WebView JS events reference

The LoyaltyLion SDK can emit various events, which can be subscribed to when you
initialize the WebView.

Listening to these events is typically not required for a basic WebView setup,
but is often used to support [advanced features](/sdk/webviews/advanced/setup)

<Warning>
  You should only subscribe to events that you intend to handle. The LoyaltyLion
  SDK checks which handlers have been registered and uses that to conditionally
  enable functionality.

  For example, free product rewards will only be
  redeemable if the appropriate events (`addCartLine`, etc) have been registered.
</Warning>

## Listening to events

The events themselves are the same for both iOS and Android, so the only difference
is how to subscribe to them.

<Tabs>
  <Tab title="iOS WKWebView">
    On iOS, we emit events using the [WKScriptMessageHandler](https://developer.apple.com/documentation/webkit/wkscriptmessagehandler) interface. Use your `WKUserContentController`
    to subscribe to the events you're interested in.

    ```swift theme={null}
    class ViewController: UIViewController, WKScriptMessageHandler {
      override func viewDidLoad() {
        let contentController = WKUserContentController()

        contentController.add(self, name: "sdkReady")
      }

      func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        if message.name == "sdkReady" {
          print("LoyaltyLion SDK is ready")
        }
      }
    }
    ```
  </Tab>
</Tabs>

## `sdkReady`

This event is emitted once the LoyaltyLion SDK has finished loading. At
this point, the [WebView JS API](/sdk/webviews/advanced/webview-js-api) can be
used to interact with the LoyaltyLion SDK running within the WebView.

### Example

<Tabs>
  <Tab title="iOS WKWebKit">
    ```swift theme={null}
    if message.name == "sdkReady" {
      print("LoyaltyLion SDK is ready")
    }
    ```
  </Tab>
</Tabs>

## `addCartLine`

This event is emitted when a shopper has redeemed a free product reward, and we
need a new line to be added to the cart for the product.

The product data will contain a hidden attribute that our Shopify Function will pick
up and automatically apply a discount to the item.

The message body will be an object containing the merchandise ID, quantity
and attributes that should be added to the cart via a
[cartLinesAdd](https://shopify.dev/docs/api/storefront/latest/mutations/cartLinesAdd)
mutation.

### Message body

<ParamField path="merchandiseId" type="string" required>
  The ProductVariant ID to add to the cart.

  Example: `gid://shopify/ProductVariant/1001`
</ParamField>

<ParamField path="productId" type="string" required>
  The Product ID to add to the cart.

  Example: `gid://shopify/Product/100`
</ParamField>

<ParamField path="quantity" type="number" required>
  The quantity of the item to add.
</ParamField>

<ParamField path="attributes" type="object" required>
  An object containing attributes that should be included with the merchandise line.

  Example:

  ```json theme={null}
  {
    "__lion_sfp_id": "19fdf4cb"
  }
  ```
</ParamField>

### Example

<Tabs>
  <Tab title="iOS WKWebKit">
    The message body will be automatically parsed, so they can
    be typecast to retrieve the values.

    ```swift theme={null}
    if message.name == "addCartLine" {
      if let body = message.body as? [String: Any],
        let merchandiseId = body["merchandiseId"] as? String,
        let quantity = body["quantity"] as? Int,
        let attributes = body["attributes"] as? [String: Any] {

        print("Adding cart line: \(merchandiseId), quantity: \(quantity)")

        // add to Shopify cart
      } else {
        print("Invalid message:", message.body)
      }
    }
    ```
  </Tab>
</Tabs>

## `removeCartLine`

This event is emitted when we need to remove a line from the cart. This
typically occurs when the shopper cancels a previously-redeemed free product
reward.

The message body will be an object containing the `lineId` that should be removed from the cart via a
[cartLinesRemove](https://shopify.dev/docs/api/storefront/latest/mutations/cartLinesRemove)
mutation.

### Message body

<ParamField path="lineId" type="string" required>
  The CartLine ID to remove from the cart.

  Example: `gid://shopify/CartLine/19fdf4cb-5495-4c2f-83d0-40c6a4898f5e`
</ParamField>

<ParamField path="merchandiseId" type="string" required>
  The ProductVariant ID of the CartLine that is being removed from the cart.

  Example: `gid://shopify/ProductVariant/1001`
</ParamField>

<ParamField path="productId" type="string" required>
  The Product ID of the CartLine that is being removed from the cart.

  Example: `gid://shopify/Product/100`
</ParamField>

<ParamField path="quantity" type="number" required>
  The quantity of the CartLine that is being removed from the cart.
</ParamField>

<ParamField path="attributes" type="object" required>
  An object containing the attributes of the CartLine that is being removed from the cart.
</ParamField>

### Example

<Tabs>
  <Tab title="iOS WKWebKit">
    The message body will be automatically parsed, so they can
    be typecast to retrieve the values.

    ```swift theme={null}
    if message.name == "removeCartLine" {
      if let body = message.body as? [String: Any],
        let lineId = body["lineId"] as? String {

        print("Removing cart line: \(lineId)")

        // remove from Shopify cart
      } else {
        print("Invalid message:", message.body)
      }
    }
    ```
  </Tab>
</Tabs>
