Wake Lock API 個案研究:BettyCrocker.com 上的購買意願指標提升了 300%

近百年來,Betty Crocker 一直是美國現代烹飪教學和值得信賴的食譜開發來源。該公司於 1997 年推出 BettyCrocker.com 網站,如今每月訪客人數超過 1, 200 萬。導入 Wake Lock API 後,與所有使用者相比,使用 Wake Lock 的使用者購買意願指標提升了約 300%。

已淘汰的 iOS 和 Android 應用程式

Betty Crocker 的應用程式於 2014 年盛大推出,但最近因優先順序降低,已從 Apple App Store 和 Google Play 商店下架。長期以來,Betty Crocker 團隊偏好在行動網站上新增功能,而非 iOS/Android 應用程式。iOS/Android 應用程式的技術平台已過時,且商家沒有資源來支援應用程式的更新和維護作業。就流量而言,網頁應用程式也明顯較大, 而且更現代化,也更容易強化。

不過,iOS/Android 應用程式確實有一項殺手級功能深受使用者喜愛:

千禧世代的烹飪專業提示:使用 @BettyCrocker 行動應用程式時,螢幕不會變暗或鎖定,—@AvaBeilke

80% 的人會在廚房使用裝置烹調料理,但螢幕變暗和鎖定是個問題。 @BettyCrocker 做了什麼? 更新應用程式,讓使用者在食譜中時,應用程式不會變暗。 —@KatieTweedy

使用 Wake Lock API 將殺手級功能帶到網頁

使用裝置烹調時,最令人沮喪的事莫過於螢幕關閉時,必須用髒手或甚至鼻子觸碰螢幕。Betty Crocker 團隊自問,如何將 iOS/Android 應用程式的殺手級功能移植到網頁應用程式。此時,他們瞭解了 Project FuguWake Lock API

一個人在沾滿麵粉的廚房餐桌上揉麵團

Wake Lock API 可防止裝置調暗或鎖定螢幕。這項功能可提供全新體驗,而這類體驗過去需要 iOS/Android 應用程式才能實現。Wake Lock API 可減少對耗電量可能較高的權宜解決方案的需求。

要求 Wake Lock

如要要求喚醒鎖定,您需要呼叫 navigator.wakeLock.request() 方法,該方法會傳回 WakeLockSentinel 物件。您會將這個物件做為哨兵值。 瀏覽器可能會因各種原因拒絕要求 (例如電池電量過低),因此建議將呼叫包裝在 try…catch 陳述式中。

釋放 Wake Lock

您還需要釋放喚醒鎖定的方法,也就是呼叫 WakeLockSentinel 物件的 release() 方法。如要在經過一段時間後自動釋放喚醒鎖定,可以使用 window.setTimeout() 呼叫 release(),如下列範例所示。

// The wake lock sentinel.
let wakeLock = null;

// Function that attempts to request a wake lock.
const requestWakeLock = async () => {
  try {
    wakeLock = await navigator.wakeLock.request('screen');
    wakeLock.addEventListener('release', () => {
      console.log('Wake Lock was released');
    });
    console.log('Wake Lock is active');
  } catch (err) {
    console.error(`${err.name}, ${err.message}`);
  }
};

// Request a wake lock…
await requestWakeLock();
// …and release it again after 5s.
window.setTimeout(() => {
  wakeLock.release();
  wakeLock = null;
}, 5000);

實作

有了這項新功能,使用者就能輕鬆瀏覽食譜、完成步驟,甚至在不鎖定螢幕的情況下離開。為達成這個目標,團隊首先建構了快速前端原型,做為概念驗證並收集使用者體驗輸入內容。

原型證明實用性後,他們設計了 Vue.js 元件,可供所有品牌 (BettyCrockerPillsburyTablespoon) 共用。雖然只有 Betty Crocker 推出 iOS 和 Android 應用程式,但這三個網站共用程式碼集,因此只要實作一次元件,就能部署到所有平台,如下方螢幕截圖所示。

BettyCrocker.com Wake Lock 切換開關
BettyCrocker.com 喚醒鎖定切換按鈕。
Pillsbury.com Wake Lock 切換
Pillsbury.com 喚醒鎖定切換按鈕。
Tablespoon.com Wake Lock 切換開關
Tablespoon.com 的 Wake Lock 切換按鈕。

根據新網站的現代化架構開發元件時,我們著重於 MVVM 模式的 ViewModel。此外,團隊在程式設計時也考量到互通性,以便在網站的舊架構和新架構上啟用功能。

為了追蹤可視性和可用性,Betty Crocker 針對喚醒鎖定生命週期中的核心事件,整合了 Analytics 追蹤功能。該團隊運用功能管理,將喚醒鎖定元件部署至單一網站,進行初步的正式版推出作業,然後監控使用情形和網頁健康狀態,再將這項功能部署至其餘網站。他們會繼續根據這個元件的使用情況監控 Analytics 資料。

為確保使用者安全,團隊建立強制逾時機制,在閒置一小時後停用喚醒鎖定。他們最終決定在網站的所有食譜頁面上,短期內導入切換按鈕。長期而言,他們希望重新設計食譜頁面檢視畫面。

Wake Lock 容器

var wakeLockControl = () => {
  return import(/* webpackChunkName: 'wakeLock' */ './wakeLock');
};

export default {
  components: {
    wakeLockControl: wakeLockControl,
  },
  data() {
    return {
      config: {},
      wakeLockComponent: '',
    };
  },
  methods: {
    init: function(config) {
      this.config = config || {};
      if ('wakeLock' in navigator && 'request' in navigator.wakeLock) {
        this.wakeLockComponent = 'wakeLockControl';
      } else {
        console.log('Browser not supported');
      }
    },
  },
};

Wake Lock 元件

<template>
  <div class="wakeLock">
    <div class="textAbove"></div>
    <label class="switch" :aria-label="settingsInternal.textAbove">
      <input type="checkbox" @change="onChange()" v-model="isChecked">
      <span class="slider round"></span>
    </label>
  </div>
</template>

<script type="text/javascript">
  import debounce from 'lodash.debounce';

  const scrollDebounceMs = 1000;

  export default {
    props: {
      settings: { type: Object },
    },
    data() {
      return {
        settingsInternal: this.settings || {},
        isChecked: false,
        wakeLock: null,
        timerId: 0,
      };
    },
    created() {
      this.$_raiseAnalyticsEvent('Wake Lock Toggle Available');
    },
    methods: {
      onChange: function() {
        if (this.isChecked) {
          this.$_requestWakeLock();
        } else {
          this.$_releaseWakeLock();
        }
      },
      $_requestWakeLock: async function() {
        try {
          this.wakeLock = await navigator.wakeLock.request('screen');
          //Start new timer
          this.$_handleAbortTimer();
          //Only add event listeners after wake lock is successfully enabled
          document.addEventListener(
            'visibilitychange',
            this.$_handleVisibilityChange,
          );
          window.addEventListener(
            'scroll',
            debounce(this.$_handleAbortTimer, scrollDebounceMs),
          );
          this.$_raiseAnalyticsEvent('Wake Lock Toggle Enabled');
        } catch (e) {
          this.isChecked = false;
        }
      },
      $_releaseWakeLock: function() {
        try {
          this.wakeLock.release();
          this.wakeLock = null;
          //Clear timer
          this.$_handleAbortTimer();
          //Clean up event listeners
          document.removeEventListener(
            'visibilitychange',
            this.$_handleVisibilityChange,
          );
          window.removeEventListener(
            'scroll',
            debounce(this.$_handleAbortTimer, scrollDebounceMs),
          );
        } catch (e) {
          console.log(`Wake Lock Release Error: ${e.name}, ${e.message}`);
        }
      },
      $_handleAbortTimer: function() {
        //If there is an existing timer then clear it and set to zero
        if (this.timerId !== 0) {
          clearTimeout(this.timerId);
          this.timerId = 0;
        }
        //Start new timer; Will be triggered from toggle enabled or scroll event
        if (this.isChecked) {
          this.timerId = setTimeout(
            this.$_releaseWakeLock,
            this.settingsInternal.timeoutDurationMs,
          );
        }
      },
      $_handleVisibilityChange: function() {
        //Handle navigating away from page/tab
        if (this.isChecked) {
          this.$_releaseWakeLock();
          this.isChecked = false;
        }
      },
      $_raiseAnalyticsEvent: function(eventType) {
        let eventParams = {
          EventType: eventType,
          Position: window.location.pathname || '',
        };
        Analytics.raiseEvent(eventParams);
      },
    },
  };
</script>

結果

Vue.js 元件已部署在所有三個網站上,並帶來出色的成效。 2019 年 12 月 10 日至 2020 年 1 月 10 日期間,BettyCrocker.com 網站的指標如下:

  • 在所有使用與 Wake Lock API 相容瀏覽器的 Betty Crocker 使用者中,有 3.5% 的使用者立即啟用這項功能,成為前 5 大動作。
  • 啟用喚醒鎖定的使用者工作階段時間長度,比未啟用者長 3.1 倍。
  • 啟用喚醒鎖定的使用者跳出率,比未使用這項功能的使用者低 50%。
  • 相較於所有使用者,使用喚醒鎖定的使用者購買意願指標高出約 300%。

3.1×

工作階段持續時間較長

50%

跳出率降低

300%

購買意願指標較高

結論

Betty Crocker 使用 Wake Lock API 後,獲得了絕佳成效。如要自行測試這項功能,請在上述任一網站 (BettyCrockerPillsburyTablespoon) 搜尋喜愛的食譜,然後啟用「烹飪時防止螢幕變暗」切換鈕。

喚醒鎖定的用途不只適用於食譜網站。其他範例包括:需要保持螢幕開啟直到條碼掃描完畢的登機證或票券應用程式、持續保持螢幕開啟的資訊站式應用程式,或是防止螢幕在簡報期間進入休眠狀態的網頁簡報應用程式。

我們已在本網站的全面性文章中,彙整您需要瞭解的 Wake Lock API 相關資訊。祝您閱讀愉快,並享受烹飪樂趣!