At a glance
| Problem it solves | Reading a raw SIP trace line by line to find why a call failed |
| What I built (new) | A browser-only tool that turns a SIP log into a call flow diagram and flags missing ACKs, error responses, retransmissions and codec mismatches |
| Built with | Claude Code (Claude Opus 5.5), plain JavaScript, no libraries |
| Time | 6 minutes from design start to a tested build, then about 11 minutes to publish (measured) |
| Try it | Live tool · Source (zip) |
What I built
I have worked on SIP systems for more than twenty years. Reading a trace always comes down to one picture: a sip call flow diagram. Who sent the INVITE? Where did the 180 come from? Did the ACK ever arrive? This project draws that picture for you. You paste a SIP log. The page draws the ladder, lists the problems it can see and shows the SDP both sides agreed on.

The important design choice is that the tool never sends your trace anywhere. SIP traces contain phone numbers, internal addresses and sometimes customer names. A tool that uploads them to a server is a tool most operators are not allowed to use. The tool’s own code makes no network requests: it has no fetch, XMLHttpRequest or similar call, and it stores nothing, so the trace is gone when you close the tab.
One caveat about this site. The live tool page sits inside this site, and the site header loads Google’s advertising script, which makes its own requests. That script is not part of the tool. If a trace must not share a page with any third-party script, download the source zip, run npm run build and open the single file it writes, dist/sip-flow-visualizer.html. That file works offline and sets a Content Security Policy with connect-src 'none' and form-action 'none', so the browser will not let it fetch, upload or submit anything.
Goal and scope
- Goal: go from “here is a trace” to “here is what went wrong” in one paste, without installing anything.
- In scope for v0.1: ladder diagram per Call-ID, problem checks, SDP offer/answer summary, click an arrow to read the full message.
- Out of scope: pcap files, SIP over TLS, vendor log layouts, RTP quality, B2BUA leg merging.
- Done means: three synthetic traces (a clean call, a busy callee, a broken call) produce the expected diagram and findings in the browser, with no requests to any other host.
Tech stack
| Part | Choice | Why |
|---|---|---|
| AI tool | Claude Code with Claude Opus 5.5 | It can run the tests and a browser itself, so it can check its own work |
| Language | Plain JavaScript, one file per job | No build chain to maintain, easy to read for network engineers |
| Drawing | Hand-written SVG | Crisp at any zoom, easy to colour for errors |
| Tests | Node.js built-in test runner | 14 tests on synthetic logs, no packages to install |
| Hosting | A WordPress page on this site | The tool sits next to the explanation |
What you need to follow along: basic JavaScript, and enough SIP to know what INVITE, 200 OK and ACK are.
How I built the SIP call flow diagram tool
The work went in five steps, and the order mattered more than the code.
First, requirements. Before any code, the AI asked me four questions. What input should the tool read? What form should it take? Which features belong in the first version? How will it be published? I answered: text logs, a browser-only page, the diagram with checks and SDP, and a public demo with source. Those answers became the first section of a one-page design document. The document also lists what the tool will deliberately not do.
Second, tests before code. The AI wrote three synthetic traces. They use only documentation addresses from RFC 5737 and example.com, so no real data can leak into the code. Then it wrote 14 tests against them and ran the tests before any module existed, to see them fail. That failing run is the proof that the tests test something.
Third, the modules. The parser turns text into messages. The model groups them into calls and transactions. The analyser applies the rules, the SDP module pairs offers with answers, and the renderer draws the SVG. All 14 tests passed on the first run. A first-run pass can also mean weak tests. So the AI opened each sample in the browser and compared every finding with the trace. They matched.
Fourth, the browser. The AI served the page locally, clicked every sample, opened message details and listed every network request the page made. The only requests were the page’s own files. That check was on the local copy, which has no ad script.
Fifth, publishing, which is where most of the trouble was. It is described below.
The prompts I used
I work in Korean, so these are faithful translations of what I actually typed.
Let's go with the SIP visualizer. Start the design.
The AI answered with the four requirement questions instead of code. That is the behaviour I want: a design question costs seconds, a wrong assumption costs a rewrite.
Go with your recommendation and publish it, but only after you have checked that it works.
This one sentence changed how the upload was done. Because “checked that it works” was a condition, the page first went up as a draft. It was tested in preview and only then published.
Show how to use it, how far it goes, and how to extend it.
That is why the tool page has a table of what the tool can and cannot do. A second table maps goals like “read my own log format” to the exact file to change.
Dead ends and fixes
Seven things went wrong. None of them was a SIP problem.
| Problem | How it was noticed | Fix |
|---|---|---|
| The test runner failed when pointed at the test folder on Node.js 25 | Running the test file directly passed all 14 tests | The test script now names the file |
| The port picked for a local preview was already used by another app | The browser showed a different app’s title | Found a free port and left the other app alone |
| Timestamps after 10 seconds were rounded, so four late messages looked simultaneous | The BYE and 200 OK rows all showed the same time | Three decimals for anything under 1000 seconds |
| Raw SIP logs carry no source or destination | Expected at design time | Requests use the top Via, responses use where their request went, and the page says “guessed” |
| The browser inside the app could not hand local files to the website | Fetch, new tab and iframe were all blocked by the browser’s local network protection | With my permission, the upload went through my normal Chrome, and each file was checked by SHA-256 after upload |
WordPress rewrote the tool’s script: every && became & and line breaks became <br> | In preview the sample buttons never appeared and the tool’s global object was undefined | The script and styles are now embedded as base64 data URLs, which WordPress leaves alone; the build fails if any character WordPress would rewrite remains |
| The tool followed my laptop’s dark mode on a light site, and the theme hid its title | Seen in the preview screenshot | The site version is fixed to the light theme and drops the duplicate title |
The WordPress one is worth remembering if you embed any script in a Custom HTML block. The block editor stores your code untouched, which makes the problem invisible in the editor. The damage happens only when the page is rendered. Always test the rendered page, not the editor.
Time and cost
| Item | Amount |
|---|---|
| Design start to tested build | 6 minutes (00:15 to 00:21 KST, measured) |
| Waiting for my review | Not work time; the session waited for my answers |
| Packaging to published page | About 11 minutes (zip built 05:56, page published 06:07 KST) |
| AI usage | Part of my Claude subscription; not metered separately for this project |
| Size | About 600 lines of JavaScript and CSS, 14 tests |
I did not time the steps inside those six minutes, so I am not quoting them. Only the timestamps above were measured.
Result
The broken sample shows what the checks are for. The second call offers only G.729 and gets an answer with only PCMU, so there is no common codec. A re-INVITE asks to put the call on hold but gets no answer in this log, and an OPTIONS request gets no response before the log ends.

The rules are deliberately conservative. A 401 or 407 challenge is shown as information, and so is a 487 after CANCEL. Both are normal parts of a call. A 2xx that is never acknowledged is an error. The sender keeps retransmitting the 200 OK and gives up after about 32 seconds, and the call drops.
The first call in the same sample is the classic dropped call. The 200 OK is sent, but no ACK for it appears in the log.
call noack-1@example.com
ERROR 2xx to INVITE (CSeq 7) was never acknowledged.
call codec-2@example.com
ERROR INVITE (CSeq 2) never got a final response.
ERROR No common codec: offer [G729] vs answer [PCMU].
WARN OPTIONS (CSeq 3) got no response.
INFO SDP puts the call on hold (sendonly / inactive / 0.0.0.0).
The sample also contains one line of plain text. The tool reports it as “could not read as SIP” with its line number, instead of dropping it silently.
The rules follow RFC 3261 for transactions and timers. SDP pairing follows RFC 3264, the offer/answer model.
- Try it: SIP Call Flow Visualizer
- Source, tests and build script: download the zip (latest version, MIT license)
Verdict
The AI was fast and careful where the problem was well defined. Parsing, grouping by branch and CSeq, drawing SVG and writing tests all worked on the first try.
It also proposed the domain rules itself: a 487 is normal, an unacknowledged 200 is not, and real data never goes into tests. Those rules match the RFCs. They have not yet been tested against real field traces, and that is where a person is still needed. A rule that is right on paper can be noisy on a live network.
The biggest time sink was not code at all. It was the last metre: getting files onto a website and surviving the site’s own filters. If you build tools like this, budget for publishing and test the page exactly as a visitor sees it.
Next step: run the tool on real field traces with private data removed, and add the rules those traces show are missing.
Update (October 8, 2026). Version 0.1.1 fixes two false alarms that turned up when the tool’s limits were measured again for the worked example on the tool page: a normal long ring (180 Ringing after a fraction of a second, then 200 OK after 40 seconds) was flagged as slow, and the placeholder address 0.0.0.0 that Trickle ICE can put in the first offer or answer of a call was reported as hold. The 14 tests described above belong to version 0.1.0; version 0.1.1 has 23.
AI disclosure: This project was built with Claude Code. The post was drafted with AI assistance. Every step, output and screenshot comes from the actual build and was reviewed by me. This revision was also drafted with AI assistance. It removes the old series label and states more precisely what the tool does and does not send over the network. J. Kim read and approved this revision on October 8, 2026. Later the same day, at J. Kim’s request, the version 0.1.1 update note was added and two sentences in the Result section were made more exact about what the log shows.



