Skip to content

Commit df44276

Browse files
author
d 🔹
authored
fix(playwright): honor user-agent from request headers (firecrawl#3387)
When scrape requests include a user-agent in the headers object, the value was silently ignored because Playwright's context-level userAgent (set from the UserAgent package) takes precedence over headers set via page.setExtraHTTPHeaders(). Fix: extract user-agent from request headers (case-insensitive) and pass it to createContext() as userAgentOverride, which replaces the randomly-generated UserAgent when present. The user-agent key is then filtered out of setExtraHTTPHeaders to avoid redundancy. When no user-agent header is provided, behavior is unchanged: a random user-agent is generated as before. Fixes firecrawl#2802
1 parent 85f221f commit df44276

1 file changed

Lines changed: 18 additions & 4 deletions

File tree

  • apps/playwright-service-ts

apps/playwright-service-ts/api.ts

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -197,8 +197,8 @@ const initializeBrowser = async () => {
197197
});
198198
};
199199

200-
const createContext = async (skipTlsVerification: boolean = false): Promise<{ context: BrowserContext; securityState: ContextSecurityState }> => {
201-
const userAgent = new UserAgent().toString();
200+
const createContext = async (skipTlsVerification: boolean = false, userAgentOverride?: string): Promise<{ context: BrowserContext; securityState: ContextSecurityState }> => {
201+
const userAgent = userAgentOverride || new UserAgent().toString();
202202
const viewport = { width: 1280, height: 800 };
203203
const securityState: ContextSecurityState = {
204204
blockedNavigationRequestUrl: null,
@@ -401,13 +401,27 @@ app.post('/scrape', async (req: Request, res: Response) => {
401401
let page: Page | null = null;
402402

403403
try {
404-
const contextBundle = await createContext(skip_tls_verification);
404+
// Extract user-agent from request headers (case-insensitive) so it can
405+
// be applied at the context level. Playwright ignores user-agent in
406+
// setExtraHTTPHeaders when the context already defines one (#2802).
407+
const userAgentOverride = headers
408+
? Object.entries(headers).find(([k]) => k.toLowerCase() === 'user-agent')?.[1]
409+
: undefined;
410+
411+
const contextBundle = await createContext(skip_tls_verification, userAgentOverride);
405412
requestContext = contextBundle.context;
406413
securityState = contextBundle.securityState;
407414
page = await requestContext.newPage();
408415

409416
if (headers) {
410-
await page.setExtraHTTPHeaders(headers);
417+
// Remove the user-agent key before calling setExtraHTTPHeaders since
418+
// we already forwarded it to the context-level userAgent option.
419+
const filteredHeaders = Object.fromEntries(
420+
Object.entries(headers).filter(([k]) => k.toLowerCase() !== 'user-agent')
421+
);
422+
if (Object.keys(filteredHeaders).length > 0) {
423+
await page.setExtraHTTPHeaders(filteredHeaders);
424+
}
411425
}
412426

413427
const result = await scrapePage(

0 commit comments

Comments
 (0)