コンテンツ レコメンデーション プロバイダである Taboola は、LoAF を使用して、パブリッシャー パートナー ウェブサイトの INP を最大 36% 改善しました。

Long Animation Frames API(LoAF)を活用し、スマートな広告枠収益化戦略を採用することで、Taboola は広告のパフォーマンスを損なうことなく、パブリッシャー様のウェブサイトの応答性を改善しました。

David Belford
David Belford

Interaction to Next Paint(INP)は、ウェブサイトがユーザー入力に応答するまでの時間を測定する指標です。INP は、ユーザーが操作(クリック、タップ、入力など)を開始してから、その結果として表示されるフィードバックまでの時間を測定します。INP は、2024 年 3 月に Core Web Vitals として First Input Delay(FID)に置き換わる予定です。

Taboola は、公開ウェブ上で毎秒 50 万件のおすすめコンテンツを提供する、世界をリードするコンテンツ ディスカバリー プラットフォームです。Taboola の 9,000 社を超える独占的なパブリッシャー パートナーは、これらの推奨事項に基づいて、オーディエンスの収益化とエンゲージメント向上を図っています。パブリッシャーは、JavaScript を使用してページにおすすめをレンダリングします。

サードパーティの JavaScript は、ページがユーザー入力にすばやく応答する能力に影響する可能性があるため、Taboola は JavaScript ファイルのサイズと実行時間を削減することに多大な投資を行ってきました。Taboola はレンダリング エンジン全体を再設計し、抽象化なしでブラウザ API を直接使用することで、INP への影響を最小限に抑えています。

このケーススタディでは、Taboola が新しい Long Animation Frames(LoAF)API を使用して、フィールドでのページの応答性に及ぼす影響を測定し、その後、特定の最適化を適用してユーザー エクスペリエンスを改善する取り組みについて説明します。

INP のプロキシとしての TBT

Total Blocking Time(TBT)は、ラボベースの指標で、ページの応答性に影響する可能性があるほど長くメインスレッドがブロックされた場所を特定します。応答性を測定するフィールド指標(INP など)は、TBT が高いと影響を受ける可能性があります。Annie Sullivan によるモバイル デバイスの TBT と INP の相関関係に関する調査では、メインスレッドのブロック時間が最小限に抑えられているサイトの方が、優れた INP スコアを達成する可能性が高いことが示されています。

この相関関係と、TBT の増加に関する Taboola のパブリッシャーの懸念から、Tabola は、この指標への貢献を最小限に抑えることに重点を置きました。

ブロックされたメインスレッドの時間に関する Lighthouse 監査のスクリーンショット。メインスレッドは、複数のスクリプトによって合計 2,630 ミリ秒ブロックされました。そのうち、サードパーティの JavaScript が 712 ミリ秒を占めています。サードパーティのブロック時間の大部分(691 ミリ秒)は、Taboola の RELEASE.js スクリプトによるものです。
Taboola の古いエンジンでは、RELEASE.js などのスクリプトがメインスレッドを 691 ミリ秒ブロックします。

Taboola は、INP の代替指標として TBT を使用して、JavaScript の実行時間をモニタリングし、最適化して、Core Web Vitals への影響を最小限に抑えるようになりました。まず、次のことを行いました。

  • Long Tasks API を使用して、フィールドで問題のあるスクリプトを特定して最適化する。
  • PageSpeed Insights API を使用して、1 日あたり 10,000 ~ 15,000 個の URL を評価し、TBT の貢献度を推定します。

ただし、Taboola では、これらのツールで TBT を分析することにはいくつかの制限があることに気づきました。

  • Long Tasks API では、タスクをオリジン ドメインまたは特定のスクリプトに関連付けることができないため、長時間実行タスクのソースを特定することが難しくなります。
  • Long Tasks API は、レンダリングの遅延を引き起こす可能性のあるタスクとレイアウト変更の組み合わせではなく、長時間実行タスクのみを特定します。

Taboola は、こうした課題に対処するため、Long Animation Frames(LoAF)API オリジン トライアルに参加して、ユーザー入力の応答性に及ぼす実際の影響を把握しました。オリジン トライアルでは、新しい機能や試験運用版の機能をご利用いただけます。デベロッパーは、ユーザーが一定期間試用できる新しい機能をテストできます。

この課題の最も難しい点は、Google 広告の KPI(重要業績評価指標)を損なうことなく、パブリッシャーのリソースの遅延を引き起こすことなく、INP を効果的に改善することです。

LoAF を使用して INP の影響を評価する

長いアニメーション フレームは、レンダリングの更新が 50 ミリ秒を超えて遅延した場合に発生します。Taboola は、タスクの長さだけでなく、ユーザー インターフェースの更新が遅い原因を特定することで、現場でのページの応答性に与える影響を分析できました。LoAF をモニタリングすることで、Taboola は次のことを実現できました。

  1. エントリを特定のタブロー タスクに関連付ける。
  2. 特定の機能のパフォーマンスの問題を本番環境にデプロイする前に確認します。
  3. 集計データを収集して A/B テストでさまざまなコード バージョンを比較し、主要な成功指標をレポートします。

次の JavaScript は、Taboola の影響を分離するために LoAF を収集するために本番環境で使用される簡素化されたバージョンです。

function loafEntryAnalysis (entry) {
  if (entry.blockingDuration === 0) {
    return;
  }

  let taboolaIsMajor = false;
  const hasInteraction = entry.firstUIEventTimestamp > 0;
  let taboolaDuration = 0;
  const nonTaboolaLoafReport = {};
  const taboolaLoafReport = {};

  entry.scripts.forEach((script) => {
    const taboolaScriptBlockingDuration = handleLongAnimationFrameScript(script, taboolaLoafReport, nonTaboolaLoafReport);
    taboolaDuration += taboolaScriptBlockingDuration;

    if (taboolaScriptBlockingDuration > 0 || taboolaDuration > entry.duration / 2) {
      taboolaIsMajor = true;
    }
  });

  generateToboolaLoafReport(taboolaLoafReport, nonTaboolaLoafReport, hasInteraction, taboolaIsMajor);

  if (hasInteraction) {
    const global = _longAnimationFramesReport.global;
    global.inpBlockingDuration = Math.max(global.inpBlockingDuration, entry.blockingDuration);

    if (taboolaIsMajor) {
      global.taboolaInpBlockingDuration = Math.max(global.taboolaInpBlockingDuration, entry.blockingDuration);
    }
  }
}

const observer = new PerformanceObserver(list => {
  for (const entry of list.getEntries()) {
    loafEntryAnalysis(entry);
  }
});

observer.observe({ type: 'long-animation-frame', buffered: true });
  • loafEntryAnalysis 関数を使用すると、Taboola が主要な貢献者であるエントリを特定できるようになりました。
  • スクリプトの合計時間の半分以上が Taboola によって発生している場合、または Taboola スクリプトの実行に 50 ミリ秒を超える時間がかかる場合は、Taboola が主な原因と見なされます。
  • 長いアニメーション フレームによりユーザー操作が遅延した場合、firstUIEventTimeStamp が生成されます。最も長いブロック時間が、全体的な INP スコアと見なされます。また、Taboola が firstUIEventTimeStamp をトリガーしたタイミングを特定して、Taboola INP スコアも計算できます。

LoAF で収集されたデータにより、Taboola は次のアトリビューション テーブルを作成しました。このテーブルでは、収益化の機会を適用できる領域を特定できます。

スクリプト 時間(ミリ秒)
vpaid/units/33_6_8/infra/cmTagINLINE_INSTREAM.js:106517 997
vpaid/units/33_6_8/infra/cmTagFEED_MANAGER.js:496662 561
vpaid/vPlayer/player/v15.8.6/OvaMediaPlayer.js:44631 336
libtrc/impl.20231212-23-RELEASE.js:821090 857
publisher_name/pmk-20220605.5.js:7728 336
libtrc/card-interference-detector.20231219-7-RELEASE.es6.js:183 239
Taboola RUM によってキャプチャされた LoAF スクリプト エントリ

TRECS Engine: 新しい収益化戦略

Taboola は、LoAF を使用してスクリプトの最適化の機会をより深く理解するだけでなく、JavaScript の実行時間とブロック時間を大幅に短縮するためにレンダリング エンジン全体を再設計しました。

TRECS(Taboola Recommendations Extensible Client Service)は、クライアントサイド レンダリングとパブリッシャーの現在の JS コードを維持しながら、Taboola のおすすめコンテンツの読み込みに必要なファイルの数とサイズを削減します。

LoAF を使用してレンダリング ブロック タスクが特定されると、「パフォーマンス フェーダー」は、scheduler.postTask() を使用してメインスレッドに降伏する前に、それらのタスクを分割できます。この設計により、メインスレッドを占有している既存のタスクに関係なく、レンダリングの更新など、ユーザー向けの重要な作業をできるだけ早く実行できます。

「パフォーマンス フェーダー」タスクランナーの JS スニペットは次のとおりです。

/**
* Send a task to run using the Fader. The task will run using the browser Scheduler, by the configuration settings, or immediately.
* @param task
* @param isBlocker
*/
function sendTaskToFader (task, isBlocker = true) {
  const publisherFaderChoice = fillOptimizationGlobals(); // Loading publisher choice
  const applyYielding = publisherFaderChoice === OptimizationFaderType.Responsiveness;

  if (applyYielding) {
    return runAsPostTask(task, isBlocker);
  }

  return runImmediately(task);
}

/**
* Yielding method using scheduler.postTask and falling back to setTimeout when it's not availabe based on the publisher choice
*/
function runAsPostTask (task, isBlocker = true) {
  if ('scheduler' in window && 'postTask' in scheduler) {
    const priority = isBlocker ? 'user-blocking': 'background';

    return window?.scheduler?.postTask(task, { priority });
  }

  const publisherChoiceEnableFallback = fillPublisherChoices();

  if (publisherChoiceEnableFallback) {
    return new Promise(resolve => {
      window.setTimeout(() => {
        resolve(task());
      }, 0);
    });
  }

  return runImmediately(task);
}

sendTaskToFader 関数:

  • runAsPostTask を使用します。runAsPostTask は、内部で scheduler.postTask() を使用します(API が利用可能な場合)。使用できない場合は setTimeout にフォールバックします。
  • この関数は、長いアニメーション フレームと INP を引き起こすコードセクションの関数呼び出しをラップします。これらのコードセクションを短いタスクに分割することで、INP を削減します。

ビジネス指標

LoAF により、Taboola は INP への影響をより詳しく把握できるようになりました。また、このツールでは、新しい TRECS エンジンの一部として使用できるスクリプトの最適化案も示されました。

TRECS とパフォーマンス フェーダーの影響を判断するため、Taboola はパブリッシャー パートナーのパネルで、スクリプト イールドのない既存のエンジンと比較して INP を測定する A/B テストを実施しました。

次の表は、Taboola ネットワーク内の 4 つの匿名パブリッシャーの 75 パーセンタイルにおける INP の結果(ミリ秒単位)を示しています。

パブリッシャー TRECS とパフォーマンス フェーダーを使用した INP 既存のエンジンを使用した INP INP の減少率(%)
パブリッシャー A 48 75 36%
パブリッシャー B 153 163 6%
パブリッシャー C 92 135 33%
パブリッシャー D 37 52 29%

幸い、テストパネルで TRECS とパフォーマンス フェーダーを有効にしても、広告のクリック率やインプレッション収益(RPM)などのビジネス指標に悪影響はありませんでした。広告の主要指標に想定どおり悪影響なしで INP が改善されたことで、Taboola はパブリッシャーが Taboola のサービスに対して抱く認識を徐々に改善しています。

前述の同じお客様で Lighthouse を再度実行したところ、新しいエンジンを使用した場合、Taboola によるメインスレッドのブロック時間が大幅に改善されました。

新しい TRECS エンジンとパフォーマンス フェーダー エンジンを適用してメインスレッドのブロック時間を改善した後、ブロックされたメインスレッドの時間に関する Lighthouse 監査のスクリーンショット。監査は、最適化前は 712 ミリ秒かかっていましたが、206 ミリ秒に短縮されました。
Taboola の新しいエンジンにより、RELEASE.js などのスクリプトの TBT が 485 ミリ秒(-70%)短縮されました。

これは、LoAF を使用して INP の原因を特定し、パフォーマンス フェーダーを使用してその後の収益化手法を導入することで、Taboola のパートナーが広告とページのパフォーマンスを最大限に高めることができることを示しています。

まとめ

INP の最適化は複雑なプロセスです。特に、パートナーのウェブサイトでサードパーティ スクリプトを使用している場合は複雑になります。最適化を開始する前に、INP を特定のスクリプトに帰属させることで、推測や他のサイトのパフォーマンス指標への損害を回避できます。LoAF API は、特に埋め込まれたサードパーティに対して、INP の問題を特定して対処するための有用なツールであることが実証されています。これにより、ページ上の他のテクノロジーからの干渉を排除しながら、特定の SDK の改善の機会を特定できます。

scheduler.postTask() の使用など、優れたレンダリング戦略と組み合わせて LoAF を使用すると、ページの応答性の低下原因を観察して把握できます。これにより、ウェブサイトの INP を改善するために必要な情報を得ることができます。

この作業にご協力いただいた Google の Gilberto Cocchi、Noam Rosenthal、Rick Viscomi 様、Taboola のエンジニアリング チームとプロダクト チームの Dedi Hakak、Anat Dagan、Omri Ariav 様に感謝いたします。