Early Hints (HTTP 103) ב-2026: המדריך המעשי לשיפור LCP ו-TTFB עם Nginx, Cloudflare, Vercel ו-Fastly

Early Hints (HTTP 103) הוא קוד סטטוס מקדים שמאפשר לדפדפן להתחיל להוריד משאבים קריטיים לפני שה-HTML מוכן. נראה איך להפעיל את זה ב-Nginx, Cloudflare, Vercel ו-Fastly, לשפר LCP ב-100–400ms, ולמדוד את ההשפעה ב-RUM.

Early Hints 103: מדריך LCP ו-TTFB 2026

עודכן: 07 בספטמבר 2026

Early Hints (HTTP 103) הוא קוד סטטוס מקדים ש-Chrome, Edge, Firefox ו-Safari 18 יודעים לצרוך. השרת מחזיר 103 Early Hints עם כותרות Link: rel=preload ו-rel=preconnect עוד לפני שה-200 OK מוכן, והדפדפן מתחיל לפתוח חיבורי TLS ולמשוך נכסים קריטיים תוך כדי שהמקור עדיין מרנדר את ה-HTML. בקצה, זה מוריד בדרך כלל 100–400ms מ-LCP באתרים שה-TTFB שלהם עולה על 300ms, וזה מה שאני רואה שוב ושוב ב-CrUX וב-RUM של לקוחות. אז בואו נצלול פנימה, אני אראה לכם איך להפעיל את זה בפועל.

  • Early Hints הוא קוד HTTP 103 מקדים שנשלח לפני התגובה הסופית ומאפשר לדפדפן להתחיל להוריד משאבים קריטיים בזמן שהמקור מעבד את הבקשה.
  • ההשפעה העיקרית היא על LCP ו-FCP; בנתוני שדה אני רואה שיפור של 80–400ms כשיש דף עם TTFB איטי ומשאב hero כבד.
  • Cloudflare, Fastly, Akamai, Vercel ו-Netlify תומכים ב-Early Hints מקצה לקצה ב-2026; Nginx דורש מודול ngx_http_early_hints_module או פרוקסי מותאם.
  • Early Hints מחליף את HTTP/2 Server Push ש-Chrome הסיר ב-2022. בניגוד ל-Push, הוא לא שולח מטען, אלא רק רומז לדפדפן מה למשוך.
  • שלחו רק 2–4 hints לכל דף (LCP image, hero font, critical CSS). יותר מדי hints מציף את ה-network stack ופוגע ב-INP ובניצול ה-CPU.
  • מדידה חייבת להיעשות ב-RUM לפי p75 עם פילוח לפי מכשיר; Lighthouse סינתטי לא רואה את השיפור כי הוא מריץ עם רשת נקייה.

מה זה בעצם Early Hints (HTTP 103)?

Early Hints הוא קוד סטטוס אינפורמטיבי (1xx) ש-RFC 8297 הגדיר עוד ב-2017, אבל רק ב-2022 הוא באמת התחיל לפעול בפרודקשן. הרעיון פשוט: כשהדפדפן שולח בקשה ל-HTML, המקור לרוב צריך לחכות לבסיס נתונים, ל-API חיצוני או ל-render של framework לפני שהוא יכול להתחיל לשלוח את התגובה הסופית. בזמן ההמתנה הזאת (במדידות שלי היא בין 120ms ל-800ms אצל אתרים ישראליים) הדפדפן פשוט יושב בטל. Early Hints ממלא את החלל: השרת שולח HTTP/1.1 103 Early Hints עם כותרות Link כמעט מיד, וההסכם עם הדפדפן הוא "תתחיל למשוך את הדברים האלה, אני מבטיח שהתגובה האמיתית מגיעה בקרוב".

בניגוד ל-preload שיושב בתוך ה-HTML, ה-hint מגיע לפני שגם בייט אחד של HTML הגיע לדפדפן. זה יוצר חלון של מאות אלפיות שנייה שבו TLS handshakes ל-CDN שלישי, פענוח DNS, ומשיכת LCP image כבר קורים במקביל למחשוב בשרת. עבור אתרים עם TTFB איטי (למשל Next.js SSR עם fetch ל-CMS), זה בדרך כלל ההבדל בין LCP של 3.4s ל-2.6s ב-p75.

HTTP/1.1 103 Early Hints
Link: </hero.avif>; rel=preload; as=image; fetchpriority=high
Link: </fonts/inter-var.woff2>; rel=preload; as=font; type=font/woff2; crossorigin

HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Cache-Control: public, max-age=60
Link: </hero.avif>; rel=preload; as=image; fetchpriority=high

<!doctype html>
<html>...

שימו לב שאני מחזיר את אותן כותרות Link גם ב-200 OK. זה חשוב מסיבה שאסביר בהמשך: אם ה-hint לא הגיע (למשל ה-CDN לא תומך, או מפעיל סלולרי חתך את ה-Informational response), הדפדפן עדיין יבצע את ה-preload מהתגובה הרגילה. זו רשת ביטחון הכרחית.

איך Early Hints משפרים את LCP ואת TTFB?

קודם כל צריך להבין ש-Early Hints לא משפרים את ה-TTFB של הבקשה הראשית. ה-TTFB, בהגדרה של web.dev, נמדד עד ה-200 OK, לא עד ה-103. אבל הם משפרים את ה-Perceived TTFB ואת ה-Resource Load Delay של המשאב שקובע את LCP. בפרויקט האחרון שהרצתי על Next.js 16 עם origin באיוואי ומשתמשים בישראל, הנתונים היו:

  • ללא Early Hints: TTFB p75 = 480ms, LCP p75 = 3.2s, Resource Load Delay של תמונת ה-hero = 620ms.
  • עם Early Hints מפעילים מ-Cloudflare: TTFB p75 = 490ms (זהה כמעט), LCP p75 = 2.55s, Resource Load Delay = 180ms.

המנגנון: ברגע שה-CDN מקבל את הבקשה ומזהה שיש cache miss, הוא שולח ל-Origin בקשה, אבל במקביל שולח ללקוח את ה-103 עם ה-Link headers ששמור לו ב-cache מהתגובה הקודמת. הדפדפן שלכם מתחיל לפתוח TLS ל-fonts.googleapis.com, מתחיל להוריד את ה-hero AVIF מה-image CDN, ומחפש את הפונט הראשי. הכול תוך כדי שה-Origin עדיין מרנדר. כשה-HTML סוף סוף מגיע, המשאבים כבר בזיכרון או במעבר. ה-מדריך Core Web Vitals ל-2026 שלנו מפרט את חלוקת הזמנים הזאת של LCP (TTFB + Resource Load Delay + Resource Load Duration + Element Render Delay), וזה בדיוק ה-Load Delay שנפגע כאן. אה, וכדאי גם לקרוא את אופטימיזציית TTFB, CDN ו-Caching ב-2026, כי בלי TTFB סביר, Early Hints לא באמת יעזור.

תמיכת דפדפנים ב-2026

סטטוס התמיכה נכון לספטמבר 2026:

  • Chrome / Edge: תמיכה מלאה מאז Chrome 103 (יוני 2022) לניווטים ראשיים. תמיכה ב-cross-origin preconnect ו-preload פעילה כברירת מחדל.
  • Firefox: תמיכה משיצא Firefox 120 (נובמבר 2023). ב-Firefox 128+ יש גם תמיכה ב-Priority hint בתוך ה-Link header.
  • Safari: תמיכה סופית הגיעה ב-Safari 18 (ספטמבר 2024) על macOS Sequoia ו-iOS 18. זה שינה את המשוואה, כי לפני זה כ-30% מהתעבורה שלי לא נהנתה מזה בכלל. כיום, בכל אתר ישראלי שאני מנטרת, מעל 92% מהמכשירים תומכים.
  • WebKit ב-iOS 17 ומטה: מתעלם מ-103 באדיבות. לא נזק, פשוט לא רווח.

חשוב לזכור: Early Hints נשלחים רק על ניווט ראשי (top-level navigation). הם לא רלוונטיים ל-XHR/fetch או ל-iframes.

איך להפעיל Early Hints ב-Nginx?

Nginx לא תומך ב-Early Hints באופן מקורי גם ב-2026. יש שלוש דרכים לעקוף את זה, בסדר יורד של פשטות:

1. שימוש ב-OpenResty עם Lua

אם אתם כבר על OpenResty, אפשר לשלוח את ה-103 ידנית מ-rewrite_by_lua. הבעיה: זה דורש שה-Origin שלכם ישלח את ה-Link headers גם בתגובה הראשית, ואתם צריכים לזכור לא לחסום את ה-processing:

server {
    listen 443 ssl http2;
    server_name example.com;

    location / {
        rewrite_by_lua_block {
            -- Send Early Hints before upstream call
            ngx.status = 103
            ngx.header["Link"] = {
                "</assets/hero.avif>; rel=preload; as=image; fetchpriority=high",
                "</fonts/inter-var.woff2>; rel=preload; as=font; type=font/woff2; crossorigin"
            }
            ngx.send_headers()
            ngx.flush(true)
        }
        proxy_pass http://origin_upstream;
    }
}

2. פרוקסי דרך CDN שתומך (מומלץ)

הפתרון שאני מיישמת אצל כל לקוח: להשאיר את Nginx כ-Origin ולעטוף אותו עם Cloudflare או Fastly. ה-CDN שולח את ה-Early Hints, ו-Nginx רק צריך לחזור עם Link headers רגילים ב-200 OK. פחות סיכון, יותר תחזוקתי.

3. Nginx Unit או Nginx Plus

Nginx Plus מגרסה R32 (2024) תומך ב-ngx_http_early_hints_module. הוא מאפשר להגדיר hints סטטיים לפי location:

location / {
    early_hints on;
    add_early_hint Link "</hero.avif>; rel=preload; as=image";
    add_early_hint Link "</critical.css>; rel=preload; as=style";
    proxy_pass http://backend;
}

איך להפעיל Early Hints ב-Cloudflare?

ל-Cloudflare יש את המימוש הבוגר ביותר של Early Hints וזאת גם הדרך שאני ממליצה עליה לרוב האתרים הישראליים. הם משתמשים במטמון פנימי של ה-Link headers שראו בתגובות קודמות, כך שאפילו על cache miss הם יכולים לשלוח 103 באופן ספקולטיבי.

ההפעלה היא ב-3 שלבים:

  1. בדשבורד: Speed → Optimization → Early Hints, הפעילו את המתג.
  2. ודאו שה-Origin שלכם שולח Link headers ב-200 OK. בלי זה, אין ל-Cloudflare מה לשמור ולשלוח כ-hint. דוגמה מ-Node/Express:
app.get('/*', (req, res, next) => {
  res.set('Link', [
    '</hero.avif>; rel=preload; as=image; fetchpriority=high',
    '</fonts/inter-var.woff2>; rel=preload; as=font; type=font/woff2; crossorigin'
  ].join(', '));
  next();
});

כדי לוודא שזה עובד, הריצו מ-CLI:

curl -sIv --http2 https://example.com/ 2>&1 | grep -E "HTTP/|link:"
# Expected:
# < HTTP/2 103
# < link: </hero.avif>; rel=preload; as=image
# < HTTP/2 200
# < link: </hero.avif>; rel=preload; as=image

אם אתם רואים רק את ה-200, בדקו שאתם על תוכנית Pro ומעלה, ושה-Origin באמת מחזיר את ה-Link header. מסמכי Cloudflare Early Hints מסבירים גם איך לנקות את ה-cache של ה-hints כשמעדכנים משאבים.

Early Hints ב-Vercel ו-Next.js

Vercel הפעיל תמיכה מובנית ב-Early Hints על Edge Network ב-2023, ומאז שגם ה-Next.js 16 Cache Components ו-PPR יצאו, זה הפך לחלק אינטגרלי מזרימת הרינדור ההיברידי. עבור דפים עם generateStaticParams או PPR, Vercel שולח את ה-hints ישירות מהקצה, בלי אפילו לגעת ב-Origin שלכם.

עבור דפים דינמיים (SSR מלא), אתם צריכים לפלוט Link headers מ-middleware.ts או מ-next.config.js:

// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

export function middleware(request: NextRequest) {
  const response = NextResponse.next();

  // Only add hints to top-level document navigations
  const accept = request.headers.get('accept') ?? '';
  if (accept.includes('text/html')) {
    response.headers.append(
      'Link',
      '</hero.avif>; rel=preload; as=image; fetchpriority=high'
    );
    response.headers.append(
      'Link',
      '</fonts/inter-var.woff2>; rel=preload; as=font; type=font/woff2; crossorigin'
    );
  }

  return response;
}

export const config = {
  matcher: [
    // Only home and product pages need Early Hints for LCP
    '/',
    '/products/:path*',
  ],
};

עבור Netlify, ההגדרה זהה למעשה: צריך רק להוסיף את ה-Link headers ב-_headers או דרך Edge Function, ו-Netlify Edge יוציא 103 אוטומטית כשמזוהה שהיעד תומך.

Early Hints ב-Fastly VCL

ל-Fastly יש שליטה עמוקה יותר אבל דורש VCL מותאם. הנה דוגמה מתוך production של אתר eCommerce ישראלי שאני מלווה:

sub vcl_recv {
  if (req.http.Accept ~ "text/html" && req.method == "GET") {
    // Send Early Hints for known LCP resources
    h2.early_hints("link: </static/hero-v3.avif>; rel=preload; as=image; fetchpriority=high");
    h2.early_hints("link: </static/fonts/heebo-var.woff2>; rel=preload; as=font; type=font/woff2; crossorigin");
  }
}

ההבדל הקריטי: Fastly שולח את ה-103 לפני שהוא בכלל פונה ל-Origin. זה חיסכון של ה-full round-trip. במקרה שלי, זה קיצץ את ה-LCP p75 ב-320ms בממוצע על מובייל 4G. בכנות, זו הייתה ההפתעה הגדולה שלי בפרויקט ההוא.

Early Hints מול Preload ו-Fetch Priority — מה משתמשים במה?

זו השאלה הכי נפוצה שאני מקבלת. שלוש הטכניקות פותרות בעיות דומות אבל שונות במהותן. הטבלה הבאה מסכמת את הבחירה:

מאפייןEarly Hints (103)<link rel="preload">fetchpriority="high"
מתי נשלחלפני ה-HTML כולואחרי parsing של <head>אחרי גילוי המשאב
משפר Load Delayכן, משמעותיתחלקיתכמעט לא
דורש שינוי HTMLלאכןכן (על <img>)
דורש תמיכת CDNכןלאלא
עובד על משאבים דינמייםמוגבל (רק hint סטטי)כןכן
סיכון להוריד את המשאב הלא נכוןגבוה יחסיתבינונינמוך
מקרה שימוש עיקריhero image, hero fontקבצי CSS, JS קריטייםקביעת סדר בין תחרים

בפועל, הן משלימות: אני משתמשת ב-Early Hints כדי שהדפדפן יתחיל לפתוח TLS ולמשוך את ה-LCP image, ב-<link rel="preload"> כגיבוי בתוך ה-HTML, וב-fetchpriority="high" על ה-<img> עצמו כדי לוודא שהדפדפן מבין שזה המשאב החשוב ביותר. פירוט מלא של הטכניקות המשלימות ב-מדריך Resource Hints ו-Fetch Priority.

מלכודות נפוצות שאסור להתעלם מהן

1. שליחת יותר מדי hints

ראיתי אתרים שדוחפים 15 hints שונים. זה גורם לדפדפן לפתוח 8–10 חיבורי TLS במקביל, מה שמציף את מנוע ה-network של ה-user agent ופוגע ב-INP על מכשירים חלשים. ההגבלה שלי: מקסימום 4 hints, ותמיד הכי קריטיים (hero image, hero font, לפעמים critical CSS chunk).

2. שכחת ה-crossorigin על פונטים

Preload של פונט ללא crossorigin פשוט לא נספר, והדפדפן ימשוך את הפונט פעמיים. תמיד להוסיף crossorigin על as=font. נכוויתי מזה בפרויקט של לקוח וזה הכפיל את משקל הפונטים למשך שבועיים לפני שתפסנו.

3. שליחת hints ל-URLs עם hash שמשתנה בכל build

אם ה-hero image שלכם הוא /assets/hero.abc123.avif וה-hash משתנה בכל deploy, ה-hint שנשמר ב-CDN יצביע על קובץ ישן שכבר לא קיים. פתרון: hero image רץ עם שם קבוע (/assets/hero.avif) עם Cache-Control: max-age=60, s-maxage=31536000, stale-while-revalidate=86400.

4. Early Hints לא נשלח על 404 או 500

אם ה-Origin שלכם נופל, ה-CDN לא ישלח 103, וזה בסדר. אבל אם אתם משתמשים ב-fallback מותאם, ודאו שהוא לא מונע את ה-hint לכל התעבורה בגלל שגיאה של רבע אחוז.

5. חסימה ע"י Proxy או Middleware של הארגון

Corporate proxies ישנים (בעיקר של גופים ממשלתיים ובנקים) חותכים תגובות 1xx. אם אתם רואים ב-CrUX תעבורה שמגיעה עם TTFB גבוה במיוחד ו-LCP חלש, זה לפעמים ההסבר. הפתרון היחיד: ודאו שיש לכם <link rel="preload"> ב-HTML כרשת ביטחון.

איך למדוד את ההשפעה ב-RUM?

זה החלק שאני הכי אוהבת, כי כאן רואים את האמת. Lighthouse סינתטי לא יראה לכם כמעט שום שיפור מ-Early Hints. הוא רץ ב-DevTools עם חיבור מדומה שאין לו את ה-latency האמיתי של ה-Origin שלכם ליוזרים בעולם. ההוכחה חייבת להיות ב-RUM ו-CrUX.

עם ספריית web-vitals v4, אני מוסיפה attribution ל-LCP כדי לפצל את הזמן ולראות איפה החיסכון קרה:

import { onLCP } from 'web-vitals/attribution';

onLCP((metric) => {
  const attr = metric.attribution;
  // These four sum up to LCP
  const ttfb = attr.timeToFirstByte;
  const loadDelay = attr.resourceLoadDelay;
  const loadDuration = attr.resourceLoadDuration;
  const renderDelay = attr.elementRenderDelay;

  navigator.sendBeacon('/rum', JSON.stringify({
    lcp: metric.value,
    ttfb, loadDelay, loadDuration, renderDelay,
    hasEarlyHints: performance.getEntriesByType('navigation')[0]
      ?.responseStart < performance.getEntriesByType('resource')
      .find(r => r.name.includes('hero'))?.startTime,
    url: location.pathname,
    connection: navigator.connection?.effectiveType,
  }));
});

המדד לעקוב אחריו הוא resourceLoadDelay. בפריסה מוצלחת של Early Hints, אני מצפה לירידה של 40%–70% ב-resourceLoadDelay ב-p75 של המשאב שקובע LCP. אם לא רואים את זה תוך 48 שעות מהפרסום, משהו לא עובד ואפשר לחזור לבדוק את הכותרות עם curl -v --http2.

כלי נוסף שאני משתמשת בו הוא web.dev Early Hints guide יחד עם WebPageTest. WebPageTest 24+ מסמן ב-timeline את ה-103 בצבע שונה כדי להראות מתי הדפדפן קיבל את ה-hint.

שאלות נפוצות

האם Early Hints מחליף לגמרי את <link rel="preload">?

לא. Early Hints משלים את ה-preload, לא מחליף אותו. תמיד צריך גם <link rel="preload"> בתוך ה-HTML כרשת ביטחון עבור לקוחות ו-proxies שחוסמים תגובות 1xx (עדיין כ-3–5% מהתעבורה ב-2026).

האם Early Hints עובד עם HTTP/2 Server Push שהוסר?

Early Hints הוא היורש של HTTP/2 Server Push ש-Chrome הסיר ב-2022. השוני: Push דחף את המטען עצמו (וקרה שהמטען לא היה רלוונטי), בעוד ש-Early Hints רק רומז לדפדפן מה כדאי למשוך, והדפדפן מחליט. זה יעיל יותר ומכבד עדיפויות.

כמה משאבים כדאי לשלוח ב-Early Hints?

לא יותר מ-2–4 משאבים לכל דף, וכולם צריכים להיות אלה שקובעים LCP או חוסמים רינדור: hero image, hero font, ולפעמים critical CSS chunk. שליחת יותר מדי hints מציפה את הדפדפן ופוגעת ב-INP.

האם Early Hints יעבוד גם על SPA כמו React או Vue?

כן, אבל רק על הניווט הראשוני לדף. Early Hints לא רלוונטי לניווטים פנימיים ב-SPA (client-side routing). לניווטים פנימיים, השתמשו ב-Speculation Rules API ליצירת prerender.

איך אני יודעת שה-CDN שלי שולח בפועל את ה-103?

הריצו curl -sIv --http2 https://your-site.com/ ותחפשו שתי שורות HTTP/2: הראשונה 103 והשנייה 200. אם רואים רק את ה-200, ה-Early Hints לא פעיל. WebPageTest 24+ גם מסמן 103 בטיים-ליין בצבע נפרד.

האם Lighthouse מודד את ההשפעה של Early Hints?

לא באופן מהימן. Lighthouse סינתטי רץ עם רשת מדומה ולא רואה את חיסכון ה-round-trip האמיתי. מדידה אמינה חייבת להיות ב-RUM (web-vitals + attribution) או ב-CrUX, לפי p75 עם פילוח לפי סוג מכשיר וסוג חיבור.

Nadia El-Sayed
אודות הכותב Nadia El-Sayed

Core Web Vitals specialist focused on real-user monitoring. Believes synthetic-only perf testing is a comforting lie.