Deterministic Diffs
Extract clean markdown so diffs are about content changes, not DOM churn.
Competitive intel is simple: extract, normalize, diff, alert. The hard part is the modern web. browser.city gives you stealth-by-default 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 apiKey = process.env.BROWSERCITY_API_KEY!;const opts = { method: "POST", headers: { Authorization: `Bearer ${apiKey}` } };const res = await fetch("https://api.browser.city/v1/requests", { ...opts, body: JSON.stringify({ url: "https://example.com/pricing", markdown: true }),}).then((r) => r.json());const md = String(res.content ?? "");const hash = createHash("sha256").update(md).digest("hex");console.log({ hash });// Compare the hash to yesterday's value and alert if different.import hashlibimport osimport requestsapi_key = os.environ["BROWSERCITY_API_KEY"]res = requests.post( "https://api.browser.city/v1/requests", headers={"Authorization": f"Bearer {api_key}"}, json={"url": "https://example.com/pricing", "markdown": True},).json()md = str(res.get("content", ""))h = hashlib.sha256(md.encode("utf-8")).hexdigest()print({"hash": h})# Compare to yesterday’s hash and alert if changed.using System.Net.Http.Headers;using System.Net.Http.Json;using System.Security.Cryptography;using System.Text;var apiKey = Environment.GetEnvironmentVariable("BROWSERCITY_API_KEY")!;var http = new HttpClient();http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", apiKey);var res = await http.PostAsJsonAsync( "https://api.browser.city/v1/requests", new { url = "https://example.com/pricing", markdown = true });var json = await res.Content.ReadFromJsonAsync<RequestResponse>() ?? throw new Exception("bad response");var md = json.content ?? "";var bytes = SHA256.HashData(Encoding.UTF8.GetBytes(md));var hash = Convert.ToHexString(bytes).ToLowerInvariant();Console.WriteLine(hash);public record RequestResponse(string? content);import java.net.URI;import java.net.http.*;import java.nio.charset.StandardCharsets;import java.security.MessageDigest;var apiKey = System.getenv("BROWSERCITY_API_KEY");var auth = "Bearer " + apiKey;var http = HttpClient.newHttpClient();var req = HttpRequest.newBuilder() .uri(URI.create("https://api.browser.city/v1/requests")) .header("Authorization", auth) .POST(HttpRequest.BodyPublishers.ofString( "{\"url\":\"https://example.com/pricing\",\"markdown\":true}")) .build();var res = http.send(req, HttpResponse.BodyHandlers.ofString());var json = res.body();var md = extractField(json, "content");var dig = MessageDigest.getInstance("SHA-256");var hashBytes = dig.digest(md.getBytes(StandardCharsets.UTF_8));System.out.println(toHex(hashBytes));static String extractField(String json, String key) { // Use a proper JSON parser in production. This is intentionally minimal. var i = json.indexOf("\"" + key + "\""); if (i < 0) return ""; var start = json.indexOf('"', i + key.length() + 2); var end = json.indexOf('"', start + 1); return (start >= 0 && end > start) ? json.substring(start + 1, end) : "";}static String toHex(byte[] bytes) { var sb = new StringBuilder(bytes.length * 2); for (byte b : bytes) sb.append(String.format("%02x", b)); return sb.toString();} Free tier. No credit card. Full stealth from day one.