GSoC Update 1: Can SVG Build Badges Update Themselves?
One of the initial goals of the project was to explore whether the SVG build
results generated by obs-status-service could become interactive and update
in real time. In particular, I wanted to determine whether an SVG embedded in a
Gitea README or comment in a PR could use JavaScript to request fresh OBS
results without requiring the user to reload the page.
Testing JavaScript Inside SVG
To verify the browser behavior, I created a small test repository containing an SVG clock. The file includes a JavaScript timer that updates the displayed date and time every second, making it immediately clear whether the script has been executed.
I tested the same SVG in several embedding contexts:
| Context | JavaScript |
|---|---|
| SVG opened directly | Runs |
SVG embedded with <object> |
Runs |
SVG embedded with <iframe> |
Runs |
SVG embedded with <img> |
Does not run |
SVG included with Markdown and rendered as <img> |
Does not run |
SVG included with Markdown and rendered as <object> |
Runs |
The important distinction is not whether SVG supports JavaScript, because it does. The restriction depends on how the browser loads the file.
When SVG is used as an image, browsers apply a restricted processing mode for security and privacy reasons. In this context, scripts and external resources are disabled. This behavior is documented by MDN’s guide to SVG as an image and by the SVG 2 conformance rules, which describe the secure image processing modes.
Gitea’s Rendering Makes the Difference
The CommonMark image specification
defines Markdown images as HTML img elements. My first test used an SVG stored
in the same repository, and Gitea kept it as img, so the script did not run.
Daniel later observed a different case on src.opensuse.org: an HTTPS SVG
badge served from the openSUSE infrastructure was embedded as an object and
did update after its 30-second timer. That distinction matters because scripts
are disabled in img, but can run when the SVG is loaded as an object.
The live
obs-git-explorer badge
confirms the second case. It is served as image/svg+xml, contains a
setInterval that runs every 30 seconds, fetches fresh results from the same
gitexplorer.opensuse.org origin, and updates its text and colors.
This also limits theme integration. An SVG image may use
prefers-color-scheme to follow the browser or operating-system preference, but
an externally loaded SVG still cannot directly reuse Gitea’s page CSS.
Implications for obs-status-service
This means live updates may be possible for obs-status-service, but only if
Gitea embeds the generated badge as object.
The practical approach would be simple:
- Serve the visible badge as SVG.
- Let the SVG JavaScript fetch the equivalent
.jsonURL. - Update the badge text and colors from that JSON response.
If Gitea keeps the badge as img, the SVG remains static and server-side
rendering is still the fallback. The key conclusion is that Markdown syntax is
not enough to decide this; the final DOM matters: img is static, while
object can support a self-updating SVG.