SIP Call Flow Diagram Tool Built with Claude Code

At a glance

Problem it solvesReading 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 withClaude Code (Claude Opus 5.5), plain JavaScript, no libraries
Time6 minutes from design start to a tested build, then about 11 minutes to publish (measured)
Try itLive 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.

SIP call flow diagram of a basic call through a proxy, drawn by the tool

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

PartChoiceWhy
AI toolClaude Code with Claude Opus 5.5It can run the tests and a browser itself, so it can check its own work
LanguagePlain JavaScript, one file per jobNo build chain to maintain, easy to read for network engineers
DrawingHand-written SVGCrisp at any zoom, easy to colour for errors
TestsNode.js built-in test runner14 tests on synthetic logs, no packages to install
HostingA WordPress page on this siteThe 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.

ProblemHow it was noticedFix
The test runner failed when pointed at the test folder on Node.js 25Running the test file directly passed all 14 testsThe test script now names the file
The port picked for a local preview was already used by another appThe browser showed a different app’s titleFound a free port and left the other app alone
Timestamps after 10 seconds were rounded, so four late messages looked simultaneousThe BYE and 200 OK rows all showed the same timeThree decimals for anything under 1000 seconds
Raw SIP logs carry no source or destinationExpected at design timeRequests 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 websiteFetch, new tab and iframe were all blocked by the browser’s local network protectionWith 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 &#038; and line breaks became <br>In preview the sample buttons never appeared and the tool’s global object was undefinedThe 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 titleSeen in the preview screenshotThe 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

ItemAmount
Design start to tested build6 minutes (00:15 to 00:21 KST, measured)
Waiting for my reviewNot work time; the session waited for my answers
Packaging to published pageAbout 11 minutes (zip built 05:56, page published 06:07 KST)
AI usagePart of my Claude subscription; not metered separately for this project
SizeAbout 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.

Problems panel and SDP negotiation table for a call with no common codec

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.

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.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top