I’m trying to write a Obsidian Web Clipper template for Gemini conversations. If anyone already did it, it would be great. I want to capture separately each user question and the corresponding gemini answer, and put each one in a callout. The html is very clean, since each user input is in an element called user-query and Gemini answers are in an element called model-response (and inside it, another element message-content contains the answer, undecorated).
So, this would produce the result I want for the first query and response:
It works nicely, but only for the first query and response. My question now is: can this be applied in loop to every pair query/response?
If I remove the filter first I get a list with all queries (or responses), but then I face two problems:
How can that list be processed element-wise to filter each element through markdown and callout? Clipper’s mini-language has a map filter, but it is not designed for this use case, I think.
How can I “interleave” queries and responses?
I realize that 2 may not be possible. In that case, can I use a “or” selector to get in a single selectorHtml both the queries and the responses? I would lose the ability to output a different callout type for each one, but that can be acceptable.
I’m posting a solution to my own question, thanks to a brilliant idea from @dawni who answered me in Obsidian’s Discord channel.
The core problem, as I suspected, is that the Web Clipper’s template language cannot map filters (like markdown or callout) over a list of elements.
The workaround is to not treat it as a list at all. Instead, you grab all the elements in order, join them into a single string, and then use a clever, two-step replace() chain.
The Working Template
Here is the final template code that works perfectly for me. (Big thanks to dawni, who suggested the replace chain idea, which I adapted slightly).
This one-liner is doing a lot, so here’s the breakdown:
selectorHtml:*:is(user-query, model-response message-content) This uses the :is() CSS selector to grab all user queries and model response content (I’m using message-content specifically to ignore the model’s “thoughts” panel and other UI elements).
| join:"" This concatenates all the found HTML elements into one single, large HTML string.
| replace:("...","...") (Part 1 - The “Pre-Hack”) This is the first key step. Before converting to Markdown, it injects unique text markers (★Gemini said and ★You said) directly into the HTML string, right before the content starts.
| markdown | blockquote This converts the entire HTML string into Markdown and then wraps the whole thing in a blockquote. This is crucial because it prefixes every line with a > .
| replace:("...","...") (Part 2 - The “Post-Hack”) This is the final step. It now searches for the markers, which (thanks to the previous filter) now look like > ★You said. It replaces these markers with the properly formatted newlines and callout headers (\n> [!user]- Query).
In my case, I use [!user] and [!gemini] callout types, which I defined via Callout Manager to have proper icons (lucide-user and lucide-stars, respectively), and I add the - that makes the callout collapsed by default, but you can adapt that to your taste.
This method completely bypasses the list-processing limitation. I hope this is helpful for anyone else facing a similar issue!