Deterministic Diffs
Extract clean markdown so diffs are about content changes, not DOM churn.
Competitive intel should be simple: extract, diff, alert. The hard part is the modern web. BrowserCity gives you bulletproof extraction primitives so your monitors don’t die quietly.
Extract clean markdown so diffs are about content changes, not DOM churn.
Competitive pages are guarded. Stealth-by-default keeps your monitors alive and your data consistent.
Most competitive intel is extraction: pricing pages, changelogs, docs, status pages. Use Request API for speed.
When competitors hide pricing behind dashboards, use Sessions (Playwright connect) and keep state across pages.
When a diff fires, grab a screenshot/PDF with Humanized REST tools for quick triage and reporting.
Competitive monitoring can be sensitive. Keep your run history and datasets out of vendor logs.
Extract markdown, hash it, and alert when it changes. Pair this with screenshots/PDF for “proof” when stakeholders ask what changed.
import { createHash } from 'node:crypto';const authorization = ['Bearer', process.env.BROWSERCITY_API_KEY].join(' ');const page = await fetch('https://api.browser.city/v1/requests', { method: 'POST', headers: { Authorization: authorization, 'Content-Type': 'application/json' }, body: JSON.stringify({ url: 'https://example.com/pricing', markdown: true }),}).then((r) => r.json());const hash = createHash('sha256').update(String(page.content ?? '')).digest('hex');console.log({ hash });import os, requests, hashlibpage = requests.post( 'https://api.browser.city/v1/requests', headers={'Authorization': f"Bearer {os.environ['BROWSERCITY_API_KEY']}"}, json={'url': 'https://example.com/pricing', 'markdown': True},).json()import hashlibhash = hashlib.sha256((page.get('content') or '').encode()).hexdigest()print({'hash': hash})using System.Net.Http.Headers;using System.Net.Http.Json;var http = new HttpClient();http.DefaultRequestHeaders.Authorization = new( "Bearer", Environment.GetEnvironmentVariable("BROWSERCITY_API_KEY"));var page = await (await http.PostAsJsonAsync( "https://api.browser.city/v1/requests", new { url = "https://example.com/pricing", markdown = true })) .Content.ReadFromJsonAsync<Response>();var hash = Convert.ToHexString(System.Security.Cryptography.SHA256.HashData( System.Text.Encoding.UTF8.GetBytes(page?.Content ?? ""))).ToLower();Console.WriteLine(hash);record Response(string? Content);import com.fasterxml.jackson.databind.ObjectMapper;import java.net.URI;import java.net.http.*;public class PricingWatch { public static void main(String[] args) throws Exception { var req = HttpRequest.newBuilder(URI.create("https://api.browser.city/v1/requests")) .header("Authorization", "Bearer %s".formatted(System.getenv("BROWSERCITY_API_KEY"))) .header("Content-Type", "application/json") .POST(HttpRequest.BodyPublishers.ofString("{\"url\":\"https://example.com/pricing\",\"markdown\":true}")) .build(); var page = new ObjectMapper().readValue( HttpClient.newHttpClient().send(req, HttpResponse.BodyHandlers.ofString()).body(), Response.class); var digest = java.security.MessageDigest.getInstance("SHA-256") .digest((page.content() == null ? "" : page.content()).getBytes(java.nio.charset.StandardCharsets.UTF_8)); System.out.println(java.util.HexFormat.of().formatHex(digest)); } record Response(String content) {}} Start for free. No credit card required. Private sessions by default.