Using the SDK for Syncs or Imports
Use the SDK to build, preview, and upload content bundles for syncs and imports.
Syncs and imports are both ways to load content into a collection. Both can create board groups, boards, sections, cards, tags, and attachments (images, PDFs, and other files). Imports are one-time, and their content is editable in Guru. Synced content is not editable in Guru, but you can run a sync again to update it.
Legacy board namingThe SDK and its preview UI predate Guru's transition from boards to folders, so its methods and output refer to "board groups" and "boards." These structures appear as folders in today's Guru.
Imports and syncs both use the same .zip format, and the SDK creates the files in that format for you. You tell the SDK what content you have and how it's structured:
- What nodes exist. Each node needs an ID and title.
- The content associated with each node, as either HTML or markdown.
- The relationship between nodes. Nodes can be nested inside each other.
The SDK figures out, based on the hierarchy you describe, which items become board groups, boards, sections, and cards. It creates the .yaml and .html files required by the import format, zips the files, and uploads them to Guru.
A full example
The script below downloads six pages from Wikipedia and imports them as a board containing six cards.
import guru
urls = [
"https://en.wikipedia.org/wiki/Odessey_and_Oracle",
"https://en.wikipedia.org/wiki/Pet_Sounds",
"https://en.wikipedia.org/wiki/London_Calling",
"https://en.wikipedia.org/wiki/24_Hour_Revenge_Therapy",
"https://en.wikipedia.org/wiki/...And_Out_Come_the_Wolves",
"https://en.wikipedia.org/wiki/Left_and_Leaving"
]
g = guru.Guru()
bundle = g.bundle("favorite_albums")
favorite_albums = bundle.node(id="albums", title="Favorite Albums")
for url in urls:
doc = guru.load_html(url)
body = doc.select(".mw-parser-output")[0]
title = doc.find(id="firstHeading").text
# remove elements we don't want in the guru card (the right column, footer links, etc.)
for el in body.select(".ambox-content, .infobox, [role='navigation'], .wikitable.floatright, #toc, .shortdescription, .hatnote"):
el.decompose()
album_node = bundle.node(
id=title,
url=url,
title=title,
content=str(body)
)
album_node.add_to(favorite_albums)
bundle.zip()
bundle.view_in_browser()Now let's step through the key pieces.
g = guru.Guru()
bundle = g.bundle("favorite_albums")A "bundle" is the SDK's name for content that can be loaded into Guru as either a sync or an import. It doesn't matter at this point which one it will be; you define the content the same way. You choose sync or import when the content is uploaded to Guru.
favorite_albums = bundle.node(id="albums", title="Favorite Albums")This creates the node we'll add the pages to. It needs an ID and a title, but since it only groups the other items, it has no HTML content of its own.
for url in urls:
doc = guru.load_html(url)
body = doc.select(".mw-parser-output")[0]
title = doc.find(id="firstHeading").text
# remove elements we don't want in the guru card (the right column, footer links, etc.)
for el in body.select(".ambox-content, .infobox, [role='navigation'], .wikitable.floatright, #toc, .shortdescription, .hatnote"):
el.decompose()We load each URL and get the page's full HTML. From this we find the article's title, then isolate the article's body in two steps: find the .mw-parser-output element, Wikipedia's container around the entire article, and remove extra elements, like the table of contents, that we don't need in the card.
album_node = bundle.node(
id=title,
url=url,
title=title,
content=str(body)
)
album_node.add_to(favorite_albums)This creates a node for the Wikipedia article, using the article's title and content. The last line adds it to our "Favorite Albums" node. Each album node becomes a card because it has HTML content; boards don't have content, only cards do. Since the album nodes are added to the favorite albums node, "Favorite Albums" becomes a board.
We don't need to tell the SDK any of this. As the content hierarchy gets more complicated, with more levels of nesting, the SDK figures out what needs to be a board group, board, or section.
bundle.zip()
bundle.view_in_browser()The call to zip() tells the SDK you're done adding content. It figures out which nodes are boards, cards, and so on, and writes the .html and .yaml files.
The call to view_in_browser() opens a preview page in your web browser so you can check the content before loading it into Guru. Some cards may look different once they're imported and viewed in Guru, but the preview is a quicker check than waiting for a full import.
Preview the bundle's content
This is what the preview page looks like:
The left side shows the content hierarchy: all board groups, boards, sections, and cards that will be created. If your content is nested deeply, the SDK uses board groups and sections to handle the extra levels. In this example we have six cards grouped under one item, so it becomes one board containing the cards.
The rest of the UI is two iframes. The left one shows the content that will be imported into Guru; the right one shows the original page. Click cards on the left to preview them, or use the up/down arrow keys to cycle through them.
The Copy Spreadsheet button in the bottom left copies a summary of the content to the clipboard so you can paste it into a spreadsheet:
When you have a lot of cards, this is an easy way to identify large articles you may want to split into multiple cards.
Updated 10 days ago

