开发者
How to Monitor Website Changes Automatically (Visual Diff Tutorial)
How to Monitor Website Changes Automatically I run a few websites and need to know immediately when something breaks. A CSS regression, a broken layout, a missing section. Manual checking doesn't scale, and text-based monitoring misses visual issues. The {{screenshot-diff}} on Apify takes two screenshots and produces a pixel-level comparison with an overlay showing exactly what changed. How It Works Take a baseline screenshot of the correct state. Then take a current screenshot of the live page. The actor compares pixel by pixel and returns a diff image with changed pixels highlighted, plus a percentage telling you how much changed. import requests , time API_TOKEN = " YOUR_APIFY_TOKEN " def capture_screenshot ( url ): resp = requests . post ( " https://api.apify.com/v2/acts/weeknds~website-screenshot-api/runs " , headers = { " Authorization " : f " Bearer { API_TOKEN } " }, json = { " url " : url , " fullPage " : True } ) run_id = resp . json ()[ " data " ][ " id " ] time . sleep ( 15 ) items = requests . get ( f " https://api.apify.com/v2/acts/weeknds~website-screenshot-api/runs/ { run_id } /dataset/items " , headers = { " Authorization " : f " Bearer { API_TOKEN } " } ). json () return items [ 0 ][ " screenshotUrl " ] def compare_screenshots ( baseline_url , current_url ): resp = requests . post ( " https://api.apify.com/v2/acts/weeknds~screenshot-comparison-tool/runs " , headers = { " Authorization " : f " Bearer { API_TOKEN } " }, json = { " baselineImageUrl " : baseline_url , " currentImageUrl " : current_url , " threshold " : 0.01 } ) run_id = resp . json ()[ " data " ][ " id " ] time . sleep ( 10 ) items = requests . get ( f " https://api.apify.com/v2/acts/weeknds~screenshot-comparison-tool/runs/ { run_id } /dataset/items " , headers = { " Authorization " : f " Bearer { API_TOKEN } " } ). json () return items [ 0 ] baseline = capture_screenshot ( " https://mysite.com " ) current = capture_screenshot ( " https://mysite.com " ) result = compare_screenshots ( b
AI 资讯
How I Built 7 Apify Actors and Started Earning Passive Income from Web Scraping
How I Built 7 Apify Actors and Started Earning Passive Income from Web Scraping A few weeks ago I had zero Apify actors. Now I have seven, all published on the Apify Store, monetized with pay-per-event pricing, and slowly building a passive income stream. Here's exactly how I did it — the strategy, the tech stack, the mistakes, and what I'd do differently. The Strategy: Zero Competition Most new Apify developers go after hot categories. LinkedIn scrapers, Amazon product extractors, Twitter data. Makes sense — those have demand. But they also have dozens of established actors with hundreds of reviews. I took the opposite approach. Find niches with zero existing actors. This means lower total addressable market, but 100% of whatever traffic exists goes to you. No competing on price, no fighting for reviews, no SEO war against actors with years of history. How I found the niches: Browsed Apify Store categories sorted by actor count Searched for common developer pain points with no existing Apify solution Checked search volume for "[keyword] API" and "[keyword] scraper" Verified zero results on Apify Store for each candidate The winners: domain intelligence, screenshot comparison, Swedish company registry, IP geolocation, QR code generation, and link metadata extraction. The Tech Stack Every actor uses the same foundation. Apify Python SDK v3.4 handles input/output, storage, proxy, and deployment. Playwright for JavaScript-heavy sites and screenshots. aiohttp for lightweight API scraping (way faster than a full browser). Pillow for image processing. Deployment is one command: apify push The Actors {{domain-intel}} WHOIS, DNS, SSL, and tech stack in one API call. Uses socket + ssl + python-whois for data collection, no external API dependency. $0.005 per run. {{screenshot-api}} Full-page screenshots via Playwright. Handles lazy-loading, infinite scroll, and viewport sizing. $0.003 per run. {{metadata-extractor}} Open Graph, Twitter Cards, JSON-LD, and meta tags from any
AI 资讯
AWS Expands DevOps Agent with AI-Powered Release Management to Validate Code Before Production
Amazon Web Services (AWS) has announced a major expansion of its AWS DevOps Agent, introducing new release management capabilities designed to assess code changes and autonomously test software before it reaches production. By Craig Risi
科技前沿
Hisense UR9 RGB MiniLED: An Affordable TV in Its Class
The brand’s UR9 competes with similar offerings from higher-end brands like Samsung and LG.
AI 资讯
15 browser-based dev tools I use daily — no login, nothing uploaded
Like most developers, I have a handful of small utilities I reach for every day — formatting JSON, decoding a JWT, generating a UUID, testing a regex. For years I just googled "json formatter" and pasted my data into whatever site came up first. Then one day I caught myself pasting a production JWT into a random online parser that POSTs everything to its server. That felt bad. So I built my own toolbox that never sends data anywhere. It's called WeTool — free, no login, and every tool runs 100% in your browser . You can open DevTools → Network and confirm there are zero requests while you use it. Here are the 15 I use most: Everyday JSON formatter / validator URL encode / decode Base64 encode / decode Timestamp ↔ date converter Security & encoding Hash calculator (MD5 / SHA) JWT parser UUID generator QR code generator Text & format Regex tester Text diff Markdown preview SQL formatter Debugging Cron expression parser Color converter User-agent parser Two things that matter to me and might to you: Nothing is uploaded. No backend, no login, no tracking of what you type. Local-only. 15 languages. Most tool boxes are English-only; this one isn't. It's free and I'm actively adding tools — if something you use daily is missing, tell me in the comments and I'll add it. 👉 wetool.site
AI 资讯
How do you dedupe support tickets that don't share any words? Here's our messy attempt.
We build an internal helpdesk, and I want to talk through a problem we only partly solved — because I suspect a lot of you have hit it too, and I'd genuinely like to hear how you handled it. The most requested thing from our users was never "better ticket forms." It was "please make the duplicates stop." Here's the shape of it. A deploy goes slightly wrong at a 40-person company. Within ten minutes you have: a handful of chat messages : "login is broken", "can't get into dashboard???", "deploy looks weird" several error-tracker events (whatever you run — Sentry, Rollbar, an APM): TokenExpiredError ×2, a 401 spike on /api/auth , a 5xx spike on auth-svc a couple of emails to IT : "access token expired", "need login reset" Nine items across three channels. One root cause: token rotation broke in that deploy. Whoever's on rotation spends the morning proving that, instead of fixing anything. We wanted to automate the recognition step — "these are the same thing" — not the fixing step. This is the honest version: what we tried, the small thing we actually shipped, and the parts we haven't cracked. If you've built something similar, I'd love to be told what we got wrong. Attempt 1: rules and keywords (broke immediately) The obvious first cut: normalize ticket text, match on keywords and categories, merge on high overlap. It fails on the example above, and it fails structurally: "login is broken" and TokenExpiredError share zero tokens. The human on rotation isn't string-matching — they know a deploy just happened, they know what auth-svc does, they've seen this failure shape before. Rules encode none of that. Rule systems also rot. Every incident teaches you a new synonym for "it's down," and six months in you own a regex museum nobody wants to touch. Maybe you've kept one of these healthy long-term — if so I'd honestly like to know how. Attempt 2: embed everything, cluster by similarity (the one we didn't ship) The tempting next move: embed ticket text, cluster on cosine
AI 资讯
British Space Startup Launches Longevity Lab Into Orbit
The lab will beam back data to train AI models to predict how proteins behind age-related diseases like Alzheimer’s and certain cancers behave.
开发者
State colocation is not a preference, it is an architecture
The first question I ask when reviewing a frontend architecture is: where does the state live relative to where it is used? In most codebases I have reviewed, the answer is "in a global store, regardless of scope." This is the wrong default. The rule State should live as close to its consumers as possible. If only one component needs it, it is component state. If a subtree needs it, it is a context or service scoped to that subtree. Global state is for truly global concerns: authentication, locale, theme.
AI 资讯
AbortController: The Async Cleanup Pattern You Keep Skipping
Most async code in frontend apps has a hidden bug: it doesn't stop when it should. A user navigates away mid-request. A component unmounts. A newer search query supersedes the previous one. The old network call keeps running, eventually resolves, and tries to update state that no longer exists. In React, that's the infamous warning: "Can't perform a React state update on an unmounted component." In vanilla JS, it silently delivers stale data. AbortController is the browser's built-in solution. It's been in every major browser since 2018 — old enough that there's no excuse not to use it. But most tutorials skip it, most codebases use it inconsistently, and most devs reach for it only after they've debugged a flicker one too many times. Here's the pattern, end to end. The race condition you already have function SearchResults ({ query }: { query : string }) { const [ results , setResults ] = useState < Result [] > ([]); useEffect (() => { fetch ( `/api/search?q= ${ query } ` ) . then ( r => r . json ()) . then ( data => setResults ( data )); // runs even if query changed }, [ query ]); return < ul > { results . map ( r => < li key = { r . id } > { r . name } </ li >) } </ ul >; } When the user types "re" and then "rea" before the first request finishes, two fetches are in flight simultaneously. The request for "re" might complete after the request for "rea" — and when it does, setResults silently overwrites the correct result with the stale one. The component shows the wrong data. No error, no warning, no clue. This is a race condition, not a hypothetical. It happens on slow networks, during fast typing, on underpowered devices, and in staging environments right before a demo. AbortController: the three-line fix An AbortController is a pair: a controller object and a signal. You pass the signal into any abort-aware API; you call abort() to cancel it. useEffect (() => { const controller = new AbortController (); fetch ( `/api/search?q= ${ query } ` , { signal : control
AI 资讯
Chrome for Developers a Berlino: cosa aspettarsi dall’ecosistema web nel 2026
Tra performance, piattaforma e toolchain: i temi che contano davvero per chi costruisce frontend oggi. Il frontend nel 2026 è diventato una disciplina sempre più “di prodotto”: non basta far funzionare l’interfaccia, serve che sia veloce, stabile, accessibile e misurabile in produzione. E quando l’ecosistema Chrome parla di “connessione” tra developer e piattaforma, il messaggio utile per chi lavora sul web è semplice: capire dove investire tempo per ottenere impatto reale sugli utenti . Di seguito, una lettura pratica dei temi che continuano a emergere come prioritari per chi costruisce applicazioni e siti moderni. 1) Performance: meno benchmark, più realtà La performance non è più un esercizio di ottimizzazione a fine progetto. È un requisito continuo che va gestito con strumenti, metriche e processi. Cosa significa “misurabile” oggi Metriche di campo (real user monitoring) : le prestazioni che contano sono quelle che arrivano dai dispositivi reali, su reti reali. Metriche di laboratorio : restano utili per regressioni e CI, ma vanno interpretate come “segnali” e non come verità assolute. Implicazione pratica Imposta una pipeline dove: le metriche sintetiche bloccano regressioni evidenti (build/PR), le metriche reali guidano le priorità (release e backlog). 2) DevTools: dal debug al controllo qualità Gli strumenti di sviluppo non servono più solo a “trovare il bug”, ma a ridurre il rischio : regressioni di layout, memory leak, risorse inutili, dipendenze pesanti. Abitudini che fanno differenza Profilare prima di ottimizzare: CPU, rete e rendering hanno colli di bottiglia diversi. Isolare i cambiamenti: una variazione di bundling o di immagini può ribaltare il profilo prestazionale più di una micro-ottimizzazione in JS. 3) La piattaforma web continua a crescere (e chiede scelte più consapevoli) La Web Platform oggi offre API potenti, ma la parte difficile non è “usarle”: è scegliere quando usarle. Un criterio utile Se una feature riduce complessità (meno librerie,
开发者
How HubSpot Scaled Semantic Search to 20 Billion Vectors
SaaS software vendor HubSpot has described how its semantic search platform grew from a proof of concept into an internal service that now manages more than 20 billion vectors across 38-plus teams. The company says the system now supports agents, RAG, and contact deduplication, and that the increase in agent usage has made retrieval quality and latency more important than before. By Matt Saunders
AI 资讯
The Troubles of Working with a Database at a Hackathon (AidStream Story)
When people talk about hackathons, they talk about the demo. The pitch, the UI, the "aha" moment on stage. Nobody really talks about the person who spent the whole weekend making sure the data didn't fall apart. That was me on AidStream, a blockchain-based aid distribution platform we built in a weekend and trust me it wasnt that easy as it seems. At a normal project, you can revisit your data model whenever.But during a hackathon you cant since when teamamtes start working on top of your tables it means both codes may start breaking . Serverless Postgres was the right choice for a hackathon: no local DB setup, no "wait, whose laptop has Postgres installed" problem. Everyone could connect to the same instance immediately. The gotcha was connection limits — with multiple people hitting the same database while testing features simultaneously, we ran into connection issues at the worst possible time (an hour before demo). So next time you watch a hackathon demo go off without a hitch, remember — someone probably spent the whole weekend quietly making sure the database didn't have a say in it. If you're the one holding the schema together at 2am, know this — it's not the flashy role, but it's the one that decides whether anyone else's code even runs.
开发者
Node.js 26: Temporal API Enabled by Default, V8 14.6, and a Round of Deprecations
Node.js 26 has been released, featuring the Temporal API enabled by default, an updated V8 engine to version 14.6, and the Undici HTTP client upgraded to 8.0. The release also removes deprecated legacy APIs. Developers should note migration points related to NODE_MODULE_VERSION changes. Node.js 26 is current for six months before entering long-term support. By Daniel Curtis
AI 资讯
The Session ID That Wouldn't Stop Changing
I was implementing a feature where the session container would track a lastActivity timestamp, updated on every authenticated request. Standard stuff. I wrote it, tested it locally with curl, and noticed something odd: I kept getting a new Set-Cookie header value on every response. Not occasionally. On every single one. A week later I was sending a pull request to mezzio/mezzio-session-cache . The Setup: Two Backends, One Session Our system had a constraint: two backend applications, written in different languages, sharing a single user session. One was the main PHP/Mezzio app. The other was a service in a different stack that needed to read from, and update the lastActivity timestamp on, the same session container. There are a few ways to make polyglot session sharing work. We landed on a shared cache backend (Redis) with a well-defined session structure. Both apps could read and write through their own libraries, as long as they agreed on the storage format and the cookie name. The session ID was the contract. That contract is the part that quietly broke. A Missing Escape Hatch My first instinct was the usual list of suspects. Was something calling regenerateId() in a middleware I didn't know about? Was there a logout being triggered somehow? Was a misconfigured cache layer evicting and recreating sessions? After a bit of digging through the call stack, I ended up in the library itself. And there it was: CacheSessionPersistence was regenerating the session ID whenever the session data changed . Not on login. Not on privilege escalation. On every write . That's when the real question hit me: why on earth would a library do that by default? Reading Code Before Changing It When you find behavior that surprises you in someone else's code, the wrong move is to immediately label it broken. The right move is to assume the maintainers had a reason, and find out what it was. The reason, in this case, is session fixation . Session fixation is a class of attack where an atta
AI 资讯
Meet HTTP QUERY: The New HTTP Method You've Probably Been Waiting For
For years, developers have faced the same dilemma when implementing complex search APIs: GET is the correct semantic choice for read-only operations, but query parameters can become extremely long and difficult to manage. POST allows sending a request body, but it's intended for operations that may change server state, making it a poor semantic fit for searches. To bridge this gap, the IETF has introduced a new HTTP method: QUERY (RFC 10008). Why was QUERY introduced? Modern APIs often require complex filtering: nested JSON filters GraphQL-like requests advanced search criteria large lists of IDs geospatial or analytical queries Encoding all of this into a URL is cumbersome and can exceed practical URI length limits. Developers have traditionally worked around this by using "POST" for read-only searches. The problem is that "POST" doesn't express the intent of the request very well. The new QUERY method solves this by allowing clients to send a request body while keeping the operation explicitly safe and idempotent. Key benefits ✅ Request body support Unlike "GET", "QUERY" allows sending structured request data in the message body, making complex searches much easier to model. ✅ Safe by design Like "GET", a "QUERY" request must not modify server state. It clearly communicates that the request is read-only. ✅ Idempotent Repeating the same "QUERY" request produces the same result without additional side effects, allowing clients and intermediaries to safely retry requests after transient failures. ✅ Cache-friendly Unlike the common "POST"-for-search pattern, "QUERY" is designed to work with HTTP caching, enabling better performance and more efficient network usage. ✅ Better API semantics Instead of overloading "POST" for read operations, APIs can now express their intent more accurately: "GET" → simple resource retrieval "QUERY" → complex read operations with a request body "POST" → operations that create or modify state Example Instead of forcing everything into a lo
AI 资讯
Python's Memory Model Is Not What You Think It Is
Python's Memory Model Is Not What You Think It Is Ask most Python developers how Python stores a variable and they will say "it stores the value." This is imprecise in a way that causes real bugs and real confusion in interviews. A precise mental model of how Python stores and retrieves data changes how you read and write code. Python does not store values in variables. Python binds names to objects. The distinction sounds philosophical until you trace code that involves mutation, function arguments, or aliasing. Then it becomes the most practically useful concept in the language. Names Are Not Boxes The box metaphor, which says a variable is a box that holds a value, is how most introductory programming courses explain variables. In many languages this metaphor is close enough to accurate that it does not cause problems. In Python it is wrong in ways that matter. A more accurate metaphor: a Python name is a label attached to an object. The object exists independently in memory. Multiple labels can be attached to the same object. Attaching a new label does not move or copy the object. x = [ 1 , 2 , 3 ] y = x print ( id ( x ) == id ( y )) # True (same object, two labels) When you write y = x , you are not copying the list. You are creating a second label that points to the exact same list object. The Four Operations You Must Distinguish 1. Assignment creates a new binding x = [ 1 , 2 , 3 ] x = [ 4 , 5 , 6 ] # x now labels a completely different object The first list still exists in memory until garbage collected. The name x simply stops pointing to it and now points to the second list. 2. Mutation modifies an existing object x = [ 1 , 2 , 3 ] x . append ( 4 ) # the object x labels is modified in place Any other name pointing to the same object will instantly reflect this change because they look at the same memory location. 3. Augmented assignment on mutable types mutates x = [ 1 , 2 , 3 ] y = x x += [ 4 , 5 ] print ( y ) # [1, 2, 3, 4, 5] (same object, mutated) The
AI 资讯
🐍 Day 1/100 — Starting my Python journey!
Hey everyone! 👋 I'm a complete beginner and today I'm officially kicking off my #100DaysOfCode challenge with Python. I've dabbled with the idea of learning to code for a while, but this time I want to actually commit - so I'm posting daily updates here to keep myself accountable and track my progress over the next 100 days. My plan: Post a short update here every day - what I learned, what I struggled with, and what's next Eventually move into some small real-world projects once I've got the basics down Why I'm doing this: I want to build real skills, not just "watch tutorials and forget everything." Writing it down publicly (even anonymously) keeps me honest and hopefully connects me with others on the same path. If you're also learning Python or doing a 100 days challenge, I'd love any tips, resources, or just to follow along with each other's progress! Day 1 status: Just setting up my environment and going through the basics — nothing exciting yet, but everyone starts somewhere! 100DaysOfCode #Python #Beginner #LearnToCode
AI 资讯
Validate Before You Build: The MVP Lessons I Learned the Hard Way
This is part of my work with 01MVP on OpenNomos — a project that helps founders validate ideas before building. The $0 Launch I once spent three months building a product. It had everything: authentication, payments, a polished UI, dark mode. I was proud of it. Launch day: 27 visitors. Zero signups. I had spent 90 days building and precisely zero days asking anyone if they wanted what I was building. I was solving a problem that existed only in my head. The Hardest Lesson The product wasn't bad. The code was fine. The UI was clean. The problem was that I never validated the core assumption: does anyone actually have this problem, and would they pay to solve it? This is the most common failure mode in indie hacking. You build something you think is cool, polish it to perfection, and launch to silence. The code was never the bottleneck. The validation was. What I Do Differently Now Talk to 10 people before writing code. Not surveys. Not landing page analytics. Actual conversations. "Would you use this? Would you pay for it? Why or why not?" Build a mockup, not a product. A Figma prototype or even a Google Form that simulates the core workflow is enough to test willingness to engage. Charge from day one. Free users will tell you nice things. Paying users will tell you the truth. If nobody will pay, the idea isn't ready. Kill fast. Most ideas fail. The goal isn't to make every idea succeed — it's to fail the bad ones quickly so you can find the good ones. Why This Matters More in 2026 In 2016, building a product was hard. You needed to know how to code, set up servers, handle deployments. The barrier to building kept bad ideas from being built. In 2026, Cursor writes your code, v0 generates your UI, and Replit deploys it. The barrier to building has collapsed to near zero. But here's the problem: AI can help you build anything. It cannot help you figure out what's worth building. The result is a flood of well-built products that nobody wants. The bottleneck shifted from
AI 资讯
"Swipe Cleaner: A Technical Deep Dive into On-Device Photo Privacy"
Disclosure: I write about projects in the OpenNomos ecosystem, including Swipe Cleaner. The Problem With Photo Cleaners Most photo cleaning apps have a dirty secret: your photos leave your device. They get uploaded to some server for "AI processing," "cloud analysis," or just because the developer didn't think about it. Swipe Cleaner takes the opposite approach. Everything happens on your iPhone. Not a single pixel leaves your device. Let me break down why that matters, and how it actually works under the hood. The Architecture Swipe Cleaner is built on three principles: 1. On-device processing, always. Image analysis, duplicate detection, and similarity matching all run locally using Apple's Core ML and Vision frameworks. No cloud roundtrips, no server costs, no privacy policy loopholes. 2. Tinder-style UX for decisions. You don't manage a grid of thumbnails and checkboxes. You swipe. Right to keep, left to delete. This isn't just a UI gimmick — it's a deliberate choice to reduce decision fatigue. When you have 3,000 photos to clean, you need flow, not friction. 3. Sandboxed storage access. The app requests permission for exactly what it needs. It doesn't ask for your entire photo library if you only want to clean screenshots. This is iOS privacy-by-design done right. Why On-Device Matters Now We're in a weird moment. AI capabilities are exploding, which means the temptation to "send it to the cloud for better results" is stronger than ever. But at the same time, Apple is pushing hard in the opposite direction — Private Cloud Compute, on-device ML, differential privacy. Swipe Cleaner aligns with where the platform is going, not where the industry has been. The Technical Trade-offs Local-first isn't free. Here's what you give up: Model size constraints. You can't run a 70B parameter vision model on an iPhone. The models need to be small, optimized, and ruthlessly efficient. No cross-device sync. Your cleaning decisions stay on one device. No cloud means no sync. For
AI 资讯
Why Online DevTools Are the Next Big Thing for Developer Productivity
Every developer has been there: you need to format a JSON blob, decode some Base64, or convert a timestamp. You open your terminal, look for the right npm package, or — worse — write a quick script. I used to do this too. Then I discovered a better pattern. The Problem with Local CLI Tools Local tools have real drawbacks: Installation overhead : npm install -g some-tool for a one-time task Version rot : tool stops working after OS update No sharing : you format JSON but cant send the result to a colleague Environment drift : works on your machine, not on staging Online Tools as a Pattern Opennomos Json (reachable via opennomos.com/en/project/01KJ850Z7PNGXHXESBM68HE12Y) represents a shift: developer tools as a platform , not as utilities you install. What makes this different: Zero install — browser tab, done Cross-device — phone, laptop, any OS Shareable results — formatted output has a URL you can send to teammates Timestamp converter built in — ms, seconds, ISO 8601, bidirectional Base64 codec — no need for a separate site The Bigger Trend We are seeing the same pattern across the dev ecosystem: GitHub Codespaces (IDE in browser), Replit (runtime in browser), Vercel (deployment in browser). The next frontier is utility tools in browser . Why run jq locally when a well-designed online tool does it faster and gives you a share link? Try It Head to opennomos.com/en/project/01KJ850Z7PNGXHXESBM68HE12Y — the JSON tools are free, fast, and part of a broader contributor rewards system that makes open-source tooling sustainable. Built as part of the Nomos Build-in-Public series.