Men-debug performa dalam kolom

Mempelajari cara mengatribusikan data performa dengan informasi debug untuk membantu mengidentifikasi dan memperbaiki masalah pengguna nyata dengan analisis

Google menyediakan dua kategori alat untuk mengukur dan melakukan debug performa:

  • Alat lab: Alat seperti Lighthouse, tempat halaman Anda dimuat di lingkungan simulasi yang dapat meniru berbagai kondisi (misalnya, jaringan lambat dan perangkat seluler kelas bawah).
  • Alat kolom: Alat seperti Laporan Pengalaman Pengguna Chrome (CrUX), yang didasarkan pada data gabungan pengguna nyata dari Chrome. (Perhatikan bahwa data kolom yang dilaporkan oleh alat seperti PageSpeed Insights dan Search Console berasal dari data CrUX.)

Meskipun alat lapangan menawarkan data yang lebih akurat, yaitu data yang benar-benar mewakili pengalaman pengguna nyata, alat lab sering kali lebih membantu Anda mengidentifikasi dan memperbaiki masalah.

Data CrUX lebih merepresentasikan performa halaman Anda yang sebenarnya, tetapi mengetahui skor CrUX kemungkinan tidak akan membantu Anda mengetahui cara meningkatkan performa.

Di sisi lain, Lighthouse akan mengidentifikasi masalah dan membuat saran khusus tentang cara meningkatkannya. Namun, Lighthouse hanya akan memberikan saran untuk masalah performa yang ditemukannya pada waktu pemuatan halaman. Fitur ini tidak mendeteksi masalah yang hanya muncul sebagai hasil dari interaksi pengguna, seperti men-scroll atau mengklik tombol di halaman.

Hal ini menimbulkan pertanyaan penting: bagaimana cara mengambil informasi debug untuk Data Web Inti atau metrik performa lainnya dari pengguna sungguhan di lapangan?

Postingan ini akan menjelaskan secara mendetail API yang dapat Anda gunakan untuk mengumpulkan informasi proses debug tambahan untuk setiap metrik Data Web Inti saat ini dan memberikan ide tentang cara mengambil data ini di alat analisis yang ada.

API untuk atribusi dan proses debug

CLS

Dari semua metrik Data Web Inti, CLS mungkin adalah metrik yang paling penting untuk mengumpulkan informasi debug di kolom. CLS diukur sepanjang masa aktif halaman, sehingga cara pengguna berinteraksi dengan halaman—seberapa jauh mereka men-scroll, apa yang mereka klik, dan sebagainya—dapat memberikan dampak yang signifikan terhadap apakah ada pergeseran tata letak dan elemen mana yang mengalami pergeseran.

Pertimbangkan laporan berikut dari PageSpeed Insights:

Laporan PageSpeed Insights dengan nilai CLS yang berbeda

Nilai yang dilaporkan untuk CLS dari lab (Lighthouse) dibandingkan dengan CLS dari kolom (data CrUX) sangat berbeda, dan ini masuk akal jika Anda menganggap bahwa halaman tersebut mungkin memiliki banyak konten interaktif yang tidak digunakan saat diuji di Lighthouse.

Namun, meskipun Anda memahami bahwa interaksi pengguna memengaruhi data kolom, Anda tetap harus mengetahui elemen apa pada halaman tersebut yang bergeser untuk menghasilkan skor 0,3 pada persentil ke-75.

Antarmuka LayoutShiftAttribution memungkinkan hal itu.

Mendapatkan atribusi pergeseran tata letak

Antarmuka LayoutShiftAttribution ditampilkan pada setiap entri layout-shift yang dikeluarkan oleh Layout Instability API.

Untuk mendapatkan penjelasan terperinci tentang kedua antarmuka ini, lihat Pergeseran tata letak debug. Untuk tujuan postingan ini, hal utama yang perlu Anda ketahui adalah, sebagai developer, Anda dapat mengamati setiap pergeseran tata letak yang terjadi di halaman serta elemen apa yang bergeser.

Berikut adalah beberapa kode contoh yang mencatat setiap pergeseran tata letak serta elemen yang bergeser:

new PerformanceObserver((list) => {
  for (const {value, startTime, sources} of list.getEntries()) {
    // Log the shift amount and other entry info.
    console.log('Layout shift:', {value, startTime});
    if (sources) {
      for (const {node, curRect, prevRect} of sources) {
        // Log the elements that shifted.
        console.log('  Shift source:', node, {curRect, prevRect});
      }
    }
  }
}).observe({type: 'layout-shift', buffered: true});

Mungkin tidak praktis untuk mengukur dan mengirim data ke alat analisis Anda untuk setiap pergeseran tata letak tunggal yang terjadi. Namun, dengan memantau semua pergeseran, Anda dapat melacak perubahan terburuk dan hanya melaporkan informasi tentang perubahan tersebut.

Sasarannya bukan untuk mengidentifikasi dan memperbaiki setiap pergeseran tata letak yang terjadi untuk setiap pengguna; tujuannya adalah untuk mengidentifikasi pergeseran yang memengaruhi jumlah pengguna terbesar dan dengan demikian memberikan kontribusi terbesar untuk CLS halaman Anda pada persentil ke-75.

Selain itu, Anda tidak perlu menghitung elemen sumber terbesar setiap kali ada perubahan, Anda hanya perlu melakukannya saat siap mengirimkan nilai CLS ke alat analisis.

Kode berikut mengambil daftar entri layout-shift yang telah berkontribusi pada CLS dan menampilkan elemen sumber terbesar dari pergeseran terbesar:

function getCLSDebugTarget(entries) {
  const largestEntry = entries.reduce((a, b) => {
    return a && a.value > b.value ? a : b;
  });
  if (largestEntry && largestEntry.sources && largestEntry.sources.length) {
    const largestSource = largestEntry.sources.reduce((a, b) => {
      return a.node && a.previousRect.width * a.previousRect.height >
          b.previousRect.width * b.previousRect.height ? a : b;
    });
    if (largestSource) {
      return largestSource.node;
    }
  }
}

Setelah mengidentifikasi elemen terbesar yang berkontribusi pada perubahan terbesar, Anda dapat melaporkannya ke alat analisis.

Elemen yang paling banyak berkontribusi pada CLS untuk halaman tertentu mungkin akan bervariasi antar-pengguna, tetapi jika menggabungkan elemen tersebut di semua pengguna, Anda akan dapat membuat daftar elemen yang bergeser yang memengaruhi jumlah pengguna terbanyak.

Setelah Anda mengidentifikasi dan memperbaiki akar masalah dari pergeseran untuk elemen-elemen tersebut, kode analisis Anda akan mulai melaporkan perubahan yang lebih kecil sebagai perubahan "terburuk" untuk halaman Anda. Pada akhirnya, semua perubahan yang dilaporkan akan cukup kecil sehingga halaman Anda berada dalam batas "baik" yaitu 0,1.

Beberapa metadata lain yang mungkin berguna untuk direkam bersama dengan elemen sumber shift terbesar adalah:

  • Waktu pergeseran terbesar
  • Jalur URL pada saat pergeseran terbesar (untuk situs yang memperbarui URL secara dinamis, seperti Aplikasi Web Satu Halaman).

LCP

Untuk men-debug LCP di kolom, informasi utama yang Anda perlukan adalah elemen tertentu yang merupakan elemen terbesar (elemen kandidat LCP) untuk pemuatan halaman tertentu.

Perhatikan bahwa sangat mungkin—pada kenyataannya, sangat umum—bahwa elemen kandidat LCP akan berbeda dari satu pengguna ke pengguna lainnya, bahkan untuk halaman yang sama persis.

Hal ini dapat terjadi karena beberapa alasan:

  • Perangkat pengguna memiliki resolusi layar berbeda, yang menyebabkan tata letak halaman berbeda, sehingga terlihat beberapa elemen di dalam area pandang.
  • Pengguna tidak selalu memuat halaman yang di-scroll ke bagian paling atas. Sering kali link akan berisi ID fragmen atau bahkan fragmen teks, yang berarti halaman Anda dapat dimuat dan ditampilkan pada posisi scroll mana pun pada halaman.
  • Konten dapat dipersonalisasi untuk pengguna saat ini, sehingga elemen kandidat LCP dapat sangat bervariasi dari satu pengguna ke pengguna lainnya.

Ini berarti Anda tidak dapat berasumsi tentang elemen atau kumpulan elemen mana yang akan menjadi elemen kandidat LCP yang paling umum untuk halaman tertentu. Anda harus mengukurnya berdasarkan perilaku pengguna yang nyata.

Mengidentifikasi elemen kandidat LCP

Untuk menentukan elemen kandidat LCP di JavaScript, Anda dapat menggunakan Largest Contentful Paint API, yaitu API yang sama dengan yang Anda gunakan untuk menentukan nilai waktu LCP.

Saat mengamati entri largest-contentful-paint, Anda dapat menentukan elemen kandidat LCP saat ini dengan melihat properti element entri terakhir:

new PerformanceObserver((list) => {
  const entries = list.getEntries();
  const lastEntry = entries[entries.length - 1];

  console.log('LCP element:', lastEntry.element);
}).observe({type: 'largest-contentful-paint', buffered: true});

Setelah mengetahui elemen kandidat LCP, Anda dapat mengirimkannya ke alat analisis beserta nilai metriknya. Seperti halnya CLS, langkah ini akan membantu Anda mengidentifikasi elemen mana yang paling penting untuk dioptimalkan terlebih dahulu.

Selain elemen kandidat LCP, sebaiknya ukur waktu sub-bagian LCP, yang dapat berguna dalam menentukan langkah pengoptimalan spesifik yang relevan untuk situs Anda.

FID

Untuk men-debug FID di lapangan, perlu diingat bahwa FID hanya mengukur bagian penundaan dari latensi peristiwa input pertama secara keseluruhan. Artinya, hal yang berinteraksi dengan pengguna tidak sepenting hal lain yang terjadi di thread utama pada saat mereka berinteraksi.

Misalnya, banyak aplikasi JavaScript yang mendukung rendering sisi server (SSR) akan mengirimkan HTML statis yang dapat dirender ke layar sebelum interaktif dengan input pengguna—yaitu, sebelum JavaScript yang diperlukan untuk membuat konten yang interaktif selesai dimuat.

Untuk jenis aplikasi ini, sangat penting untuk mengetahui apakah input pertama terjadi sebelum atau setelah hidrasi. Jika ternyata banyak orang yang mencoba berinteraksi dengan halaman sebelum hidrasi selesai, pertimbangkan untuk merender halaman Anda dalam status nonaktif atau pemuatan, bukan dalam status yang terlihat interaktif.

Jika framework aplikasi menampilkan stempel waktu hidrasi, Anda dapat membandingkannya dengan stempel waktu entri first-input untuk menentukan apakah input pertama terjadi sebelum atau setelah hidrasi. Jika framework Anda tidak mengekspos stempel waktu tersebut, atau tidak menggunakan hidrasi sama sekali, sinyal berguna lainnya mungkin berupa input yang terjadi sebelum atau setelah JavaScript selesai dimuat.

Peristiwa DOMContentLoaded diaktifkan setelah HTML halaman dimuat dan diuraikan sepenuhnya, yang mencakup menunggu skrip sinkron, ditangguhkan, atau modul (termasuk semua modul yang diimpor secara statis) dimuat. Anda dapat menggunakan waktu peristiwa itu dan membandingkannya dengan saat FID terjadi.

Kode berikut mengamati entri dan log first-input apakah input pertama terjadi sebelum akhir peristiwa DOMContentLoaded:

new PerformanceObserver((list) => {
  const fidEntry = list.getEntries()[0];
  const navEntry = performance.getEntriesByType('navigation')[0];
  const wasFIDBeforeDCL =
    fidEntry.startTime < navEntry.domContentLoadedEventStart;

  console.log('FID occurred before DOMContentLoaded:', wasFIDBeforeDCL);
}).observe({type: 'first-input', buffered: true});

Mengidentifikasi elemen target dan jenis peristiwa FID

Sinyal debug tambahan yang berpotensi berguna adalah elemen yang menerima interaksi serta jenis interaksinya (seperti mousedown, keydown, pointerdown). Meskipun interaksi dengan elemen itu sendiri tidak berkontribusi pada FID (perlu diingat, FID hanyalah bagian penundaan dari total latensi peristiwa), mengetahui elemen mana yang berinteraksi dengan pengguna Anda mungkin akan berguna dalam menentukan cara terbaik untuk meningkatkan FID.

Misalnya, jika sebagian besar interaksi pertama pengguna Anda adalah dengan elemen tertentu, pertimbangkan untuk menyisipkan kode JavaScript yang diperlukan untuk elemen tersebut di HTML, dan pemuatan lambat sisanya.

Untuk mendapatkan jenis dan elemen interaksi yang terkait dengan peristiwa input pertama, Anda dapat mereferensikan properti target dan name entri first-input:

new PerformanceObserver((list) => {
  const fidEntry = list.getEntries()[0];

  console.log('FID target element:', fidEntry.target);
  console.log('FID interaction type:', fidEntry.name);
}).observe({type: 'first-input', buffered: true});

INP

INP sangat mirip dengan FID karena bit informasi yang paling berguna untuk ditangkap di lapangan adalah:

  1. Elemen apa yang berinteraksi
  2. Mengapa jenis interaksi tersebut
  3. Kapan interaksi itu terjadi

Seperti FID, penyebab utama interaksi yang lambat adalah thread utama yang diblokir, yang sering terjadi saat JavaScript dimuat. Mengetahui apakah sebagian besar interaksi lambat terjadi selama pemuatan halaman akan membantu menentukan tindakan yang perlu dilakukan untuk memperbaiki masalah.

Tidak seperti FID, metrik INP mempertimbangkan latensi penuh interaksi—termasuk waktu yang diperlukan untuk menjalankan pemroses peristiwa yang terdaftar serta waktu yang diperlukan untuk menggambar frame berikutnya setelah semua pemroses peristiwa berjalan. Artinya, bagi INP, akan lebih berguna lagi untuk mengetahui elemen target mana yang cenderung menghasilkan interaksi yang lambat, dan jenis interaksi yang dimaksud.

Karena INP dan FID didasarkan pada Event Timing API, cara Anda menentukan informasi ini di JavaScript sangat mirip dengan contoh sebelumnya. Kode berikut mencatat elemen dan waktu target (relatif terhadap DOMContentLoaded) entri INP ke dalam log.

function logINPDebugInfo(inpEntry) {
  console.log('INP target element:', inpEntry.target);
  console.log('INP interaction type:', inpEntry.name);

  const navEntry = performance.getEntriesByType('navigation')[0];
  const wasINPBeforeDCL =
    inpEntry.startTime < navEntry.domContentLoadedEventStart;

  console.log('INP occurred before DCL:', wasINPBeforeDCL);
}

Perlu diperhatikan bahwa kode ini tidak menunjukkan cara menentukan entri event mana yang merupakan entri INP, karena logika tersebut lebih terlibat. Namun, bagian berikut menjelaskan cara mendapatkan informasi ini menggunakan library JavaScript web-vitals.

Penggunaan dengan library JavaScript web-vitals

Bagian di atas menawarkan beberapa saran umum dan contoh kode untuk mengambil info debug agar disertakan dalam data yang Anda kirim ke alat analisis.

Sejak versi 3, library JavaScript web-vitals menyertakan build atribusi yang menampilkan semua informasi ini, dan juga beberapa sinyal tambahan.

Contoh kode berikut menunjukkan cara menetapkan parameter peristiwa tambahan (atau dimensi kustom) yang berisi string debug yang berguna untuk membantu mengidentifikasi penyebab utama masalah performa.

import {onCLS, onFID, onINP, onLCP} from 'web-vitals/attribution';

function sendToGoogleAnalytics({name, value, id, attribution}) {
  const eventParams = {
    metric_value: value,
    metric_id: id,
  }

  switch (name) {
    case 'CLS':
      eventParams.debug_target = attribution.largestShiftTarget;
      break;
    case 'LCP':
      eventParams.debug_target = attribution.element;
      break;
    case 'FID':
    case 'INP':
      eventParams.debug_target = attribution.eventTarget;
      break;
  }

  // Assumes the global `gtag()` function exists, see:
  // https://developers.google.com/analytics/devguides/collection/ga4
  gtag('event', name, eventParams);
}

onCLS(sendToGoogleAnalytics);
onLCP(sendToGoogleAnalytics);
onFID(sendToGoogleAnalytics);
onINP(sendToGoogleAnalytics);

Kode ini khusus untuk Google Analytics, tetapi ide umumnya juga harus diterjemahkan ke alat analisis lainnya.

Kode ini juga hanya menunjukkan cara melaporkan satu sinyal debug, tetapi mungkin berguna untuk dapat mengumpulkan dan melaporkan beberapa sinyal berbeda per metrik. Misalnya, untuk men-debug INP, Anda mungkin perlu mengumpulkan jenis interaksi, waktu, dan juga elemen yang berinteraksi. Build atribusi web-vitals mengekspos semua informasi ini, seperti yang ditunjukkan pada contoh berikut:

import {onCLS, onFID, onINP, onLCP} from 'web-vitals/attribution';

function sendToGoogleAnalytics({name, value, id, attribution}) {
  const eventParams = {
    metric_value: value,
    metric_id: id,
  }

  switch (name) {
    case 'INP':
      eventParams.debug_target = attribution.eventTarget;
      eventParams.debug_type = attribution.eventType;
      eventParams.debug_time = attribution.eventTime;
      eventParams.debug_load_state = attribution.loadState;
      break;

    // Additional metric logic...
  }

  // Assumes the global `gtag()` function exists, see:
  // https://developers.google.com/analytics/devguides/collection/ga4
  gtag('event', name, eventParams);
}

onCLS(sendToGoogleAnalytics);
onLCP(sendToGoogleAnalytics);
onFID(sendToGoogleAnalytics);
onINP(sendToGoogleAnalytics);

Lihat dokumentasi atribusi web-vitals untuk mengetahui daftar lengkap sinyal debug yang diekspos.

Melaporkan dan memvisualisasikan data

Setelah Anda mulai mengumpulkan informasi debug bersama dengan nilai metrik, langkah selanjutnya adalah menggabungkan data dari semua pengguna untuk mulai mencari pola dan tren.

Seperti yang disebutkan di atas, Anda tidak perlu mengatasi setiap masalah yang dihadapi pengguna. Sebaiknya Anda mengatasi—terutama pada tahap awal—masalah yang memengaruhi jumlah pengguna terbesar, yang juga seharusnya merupakan masalah yang memiliki dampak negatif terbesar pada skor Data Web Inti Anda.

Untuk GA4, lihat artikel khusus tentang cara membuat kueri dan memvisualisasikan data menggunakan BigQuery.

Ringkasan

Semoga postingan ini telah membantu menjelaskan cara spesifik penggunaan API performa yang ada dan library web-vitals untuk mendapatkan informasi debug guna membantu mendiagnosis performa berdasarkan kunjungan pengguna yang sebenarnya di lapangan. Meskipun panduan ini difokuskan pada Data Web Inti, konsepnya juga berlaku untuk proses debug metrik performa apa pun yang dapat diukur dalam JavaScript.

Jika Anda baru saja mulai mengukur performa, dan sudah menjadi pengguna Google Analytics, alat Laporan Data Web mungkin bisa menjadi pilihan yang tepat untuk memulai, karena sudah mendukung pelaporan informasi debug untuk metrik Core Web Vitals.

Jika Anda adalah vendor analisis dan ingin meningkatkan kualitas produk dan memberikan lebih banyak informasi proses debug kepada pengguna, pertimbangkan beberapa teknik yang dijelaskan di sini, tetapi jangan batasi hanya ide-ide yang ditampilkan di sini. Postingan ini dimaksudkan agar berlaku secara umum untuk semua alat analisis; namun, setiap alat analisis kemungkinan dapat (dan seharusnya) mengambil dan melaporkan lebih banyak lagi informasi debug.

Terakhir, jika Anda merasa ada kesenjangan dalam kemampuan untuk men-debug metrik ini karena fitur atau informasi yang tidak ada dalam API itu sendiri, kirimkan masukan Anda ke web-vitals-feedback@googlegroups.com.