---
title: "Hootbox | Smart Popup Element & Popup Builder for YOOtheme Pro"
description: "Create smart popups in YOOtheme Pro with any content, flexible triggers, timing, frequency controls and targeting options. Try the live demo first."
url: "https://www.yoozecase.com/?item_id=28"
date: "2026-09-22T03:53:44+00:00"
language: "en-GB"
---

#  Hootbox

It's like a box of chocolates, you never know what you're gonna get!

**Latest Version**
1.0
**Release date**
07 September 2026
**Made for**
Yootheme Pro, Joomla, Wordpress
**Price**
€15.00 (incl. 6 months of updates)

 [ 🛒 Get it for Joomla 👍 ](https://yoozecase.lemonsqueezy.com/checkout/buy/dafe534a-e23c-4e8a-85d3-471c792f73b5)

 [ 🛒 Get it for WordPress👍 ](https://yoozecase.lemonsqueezy.com/checkout/buy/ac73ea2f-a9dd-48e4-95a4-1720a40492ee)

 [ Demo page ](https://www.yoozecase.com/hootbox-demo)

The smart popup element for YOOtheme Pro. Place any content, then decide when it appears, how often, and who sees it.

 ![Hootbox](https://www.yoozecase.com/files/hootbox.png)

 [](#)

 [](#)

---

##  Description

HootBox is the smart popup element for YOOtheme Pro. You build the popup in the builder like any other section, with text, images, video, a form or a module inside it, and then you decide the part that actually matters: when it appears, how often, and who gets to see it.

A popup does not have to be a box in the middle of the screen. Pick a centred dialog when you need an answer, a bar for an announcement, a corner panel for a quiet hint, a side panel for a form, or a full screen welcome mat. Ten placements in total, each one using the card styles of your theme, so it matches the rest of the site without a line of extra CSS.

Timing is where a smart popup earns its keep. Open on page load after a delay, at a scroll depth, when a chosen element comes into view, on exit intent, after a period of inactivity, or on a click on any link or button you point at. Give it a start and an end date, weekdays and a daily time window, and the Christmas banner disappears on the twenty sixth without anyone logging in.

Then decide how often. Every page load, once per session, once per visitor, or again after a number of days. Cap the number of views, choose whether a view counts on open, on close or only after a button click, and add a do not show again checkbox for the people who mean it. All of it is stored in the browser of the visitor: no cookies, nothing sent to a server, nothing to declare in a privacy statement.

Show it to guests only or to logged in users only, limit it to phones or desktops, give phones a bottom bar instead of a blocking modal, and match the language of the page, a campaign parameter in the address or the site the visitor came from.

Built to keep you out of trouble: the defaults follow Google's guidance on intrusive interstitials, a blocking popup is a real dialog with focus handling and an Escape route, and visitors who ask their system for less motion get no animation at all.

One element, one licence, the same behaviour on Joomla and on WordPress.

##  Feature request

 ### What is the next feature for this plugin?

Submit your idea or vote on existing ones.

  #### Top voted

   Website (leave empty)

'; } html += ''; if (oc.title) { html += '##### ' + escapeHtml(oc.title) + '

'; } if (oc.text) { html += '' + escapeHtml(oc.text).replace(/\\n/g, '
') + '

'; } html += '

'; } // Auto winner(s) - top N from the already vote-sorted features if (mode === 'auto_winner' || mode === 'both') { var n = oc.winnerCount | 0; if (n '; for (var i = 0; i ' + (w.image_url ? '![](https://www.yoozecase.com/'%20+%20escapeHtml(w.image_url)%20+%20')

' : '') + '' + (i + 1) + '' + '' + escapeHtml(w.title) + '' + '' + getIcon(this.cfg.voteIcon) + ' ' + (w.votes | 0) + '' + ''; } html += ''; } } if (html === '') { this.elOutcome.hidden = true; return; } this.elOutcome.innerHTML = html; this.elOutcome.hidden = false; }; /** * Roadmap view (v3.2.0): renders the items as status columns, in the * canonical status order from cfg.statuses. Each column is an 12. inside \* the existing .yc-fb-list , holding its own inner  of items - \* this keeps the delegated click/change handlers on elList working \* unchanged. Unknown statuses fall back into the "open" column so no item \* can silently disappear. Empty columns are skipped when \* cfg.roadmapHideEmpty is set. \*/ Board.prototype.renderRoadmap = function (items) { var stats = (this.cfg.statuses && this.cfg.statuses.length) ? this.cfg.statuses : \['open', 'planned', 'in\_progress', 'shipped', 'declined'\]; var labels = this.cfg.statusLabels || {}; var groups = {}; var i, st; for (i = 0; i ' + '##### ' + '' + escapeHtml(labels\[sv\] || sv) + '' + arr.length + '' + '

    ' + '' + itemsHtml + '
    ' + '
'; } return html; }; Board.prototype.renderItem = function (f, index) { var disabled = this.cfg.isClosed ? 'disabled' : ''; var voted = f.voted ? ' yc-voted' : ''; var descHtml = f.description ? '' + escapeHtml(f.description).replace(/\\n/g, '
') + '

' : ''; var thumbHtml = f.image_url ? '![](https://www.yoozecase.com/'%20+%20escapeHtml(f.image_url)%20+%20')

' : ''; // Status workflow (v3.0.0): badge for any non-default status. The // roadmap view (v3.2.0) skips the badge - the column already // communicates the status, a badge would be redundant noise. var st = (f.status || 'open'); var labels = this.cfg.statusLabels || {}; var statusBadge = (!this.isRoadmap && st && st !== 'open' && labels[st]) ? '' + escapeHtml(labels\[st\]) + '' : ''; // Design themes (v3.1.0): arena / neon / pixel render extra per-item // furniture - rank number, avatar (image or initials), a "leader" pill // on rank 1, and a "votes" label. Classic/colour themes are untouched. var t = this.cfg.theme || 'light'; var themed = (t === 'arena' || t === 'neon' || t === 'pixel'); var rank = (typeof index === 'number') ? (index + 1) : 0; var rankHtml = '', leaderHtml = '', avatarHtml = '', votesLabel = ''; if (themed) { rankHtml = '' + pad2(rank) + ''; if (rank === 1) { leaderHtml = '' + escapeHtml(this.cfg.leaderLabel || 'Leader') + ''; } if (f.image_url) { avatarHtml = '![](https://www.yoozecase.com/'%20+%20escapeHtml(f.image_url)%20+%20')

'; } else { avatarHtml = '' + escapeHtml(initialsOf(f.title)) + '

'; } votesLabel = '' + escapeHtml(this.cfg.votesLabel || 'votes') + ''; } // Moderation overlay: subtle corner buttons, only when canModerate. // Buttons appear on hover/focus (styled in CSS). Even in customizer // preview we render them when canModerate is true so the moderator // can see what visitors with moderation rights will see. var modHtml = ''; if (this.cfg.canModerate) { var parts = []; var hideTitle = escapeHtml(this.t('hideTitle', 'Hide this feature')); var deleteTitle = escapeHtml(this.t('deleteTitle', 'Delete this feature')); if (this.cfg.allowSoftHide) { parts.push( '' ); } if (this.cfg.allowHardDelete) { parts.push( '' ); } if (parts.length || (this.cfg.statuses && this.cfg.statuses.length)) { var sParts = parts.slice(); if (this.cfg.statuses && this.cfg.statuses.length) { var opts = ''; for (var si = 0; si ' + escapeHtml(sl) + ''; } var setStatus = escapeHtml(this.t('setStatus', 'Set status')); sParts.push( '' ); } modHtml = '' + sParts.join('') + '

'; } } var mediaHtml = themed ? avatarHtml : thumbHtml; return ( '32. ' + leaderHtml + rankHtml + '' + mediaHtml + '' + '##### ' + escapeHtml(f.title) + '

    ' + statusBadge + descHtml + '

    ' + modHtml + '
' ); }; /** * Detects whether a JSON response looks like a CSRF/token rejection. * Two cases: * 1. com_ajax-level rejection (Joomla's auto-token-check on POST): top * level message contains the JINVALID_TOKEN_NOTICE text and HTTP * status is typically 403. * 2. Plugin-level rejection from requireToken(): payload.error === "Invalid token". */ Board.prototype.isTokenError = function (status, raw, payload) { if (status === 403) return true; var hay = ''; try { hay = JSON.stringify(raw || {}) + '|' + JSON.stringify(payload || {}); } catch (e) {} return /invalid (security )?token/i.test(hay); }; /** * Fetch a fresh CSRF token from the server. Updates this.cfg.csrfToken so * the next call (and any future calls in this Board's lifetime) use the * correct one. Cache-bust with a timestamp so no upstream CDN caches the * response. */ Board.prototype.fetchFreshToken = function () { var self = this; var url = this.cfg.ajaxUrl + '&task=token&_=' + Date.now(); return fetch(url, { method: 'GET', credentials: 'same-origin', headers: { 'Accept': 'application/json', 'Cache-Control': 'no-cache' } }) .then(function (r) { return r.json(); }) .then(function (data) { var p = self.unwrapAjax(data); if (p && p.ok === true && typeof p.token === 'string' && p.token.length >= 16) { self.cfg.csrfToken = p.token; return p.token; } throw new Error('No fresh token in response'); }); }; /** * Generic POST-with-token helper. Builds FormData from a plain object, * adds the current token, posts. On 403 / token-error response, fetches a * fresh token and retries exactly once. * * @param {string} task The task name (appended to URL and body) * @param {object} fields Key-value form fields (no token) * @return {Promise} Resolves to the unwrapped payload on success. \* Rejects with Error containing .reason on failure. \*/ Board.prototype.postWithToken = function (task, fields) { var self = this; function attempt(token) { var fd = new FormData(); fd.append('task', task); for (var k in fields) { if (Object.prototype.hasOwnProperty.call(fields, k)) { fd.append(k, fields\[k\]); } } fd.append(token, '1'); return fetch(self.cfg.ajaxUrl + '&task=' + encodeURIComponent(task), { method: 'POST', credentials: 'same-origin', body: fd, headers: { 'Accept': 'application/json' } }).then(function (r) { return r.json().then(function (data) { return { status: r.status, raw: data, payload: self.unwrapAjax(data) }; }); }); } return attempt(this.cfg.csrfToken).then(function (res) { // Success path if (res.payload && res.payload.ok === true) { return res.payload; } // Token rejection? Fetch fresh and retry once. if (self.isTokenError(res.status, res.raw, res.payload)) { return self.fetchFreshToken().then(function (fresh) { return attempt(fresh).then(function (res2) { if (res2.payload && res2.payload.ok === true) { return res2.payload; } var err = new Error( (res2.payload && res2.payload.error) || (res2.raw && res2.raw.message) || self.t('requestFailed', 'Request failed.') ); err.payload = res2.payload || null; throw err; }); }); } // Some other error - surface it var err = new Error( (res.payload && res.payload.error) || (res.raw && res.raw.message) || self.t('requestFailed', 'Request failed.') ); err.payload = res.payload || null; throw err; }); }; Board.prototype.handleSubmit = function () { var self = this; if (isInBuilder()) { this.showStatus(this.t('previewSubmit', 'Preview mode - submissions are disabled in the YOOtheme builder. Try this on the published page.'), 'info'); return; } if (this.cfg.isClosed) { this.showStatus(this.cfg.closedMessage || this.t('votingClosed', 'Voting is closed.'), 'info'); return; } var title = (this.elTitle && this.elTitle.value || '').trim(); var desc = (this.elDesc && this.elDesc.value || '').trim(); // Client-side validation: minimum title length. Server re-validates. var minLen = (this.cfg.minTitleLength | 0) || 2; if (title.length for hide/delete, remember parent + sibling for rollback. var li = btn.closest('li'); var parentEl = li ? li.parentNode : null; var nextEl = li ? li.nextSibling : null; if (li && (action === 'hide' || action === 'delete')) { li.remove(); } btn.disabled = true; var task = action === 'hide' ? 'moderate\_hide' : action === 'delete' ? 'moderate\_delete' : action === 'restore' ? 'moderate\_restore' : ''; if (!task) { btn.disabled = false; return; } this.postWithToken(task, { feature\_id: featureId }) .then(function (payload) { // Success - keep the UI as-is (already removed) and refresh // so vote counts, top box, and hidden-features panel reflect // the new state. self.refresh(); if (self.hiddenOpen) { self.hiddenLoaded = false; // force a refetch self.fetchHiddenFeatures(); } var msg = action === 'delete' ? self.t('deleted', 'Feature deleted.') : action === 'hide' ? self.t('hidden', 'Feature hidden.') : action === 'restore' ? self.t('restored', 'Feature restored.') : self.t('done', 'Done.'); self.showStatus(msg, 'success'); setTimeout(function () { self.hideStatus(); }, 3000); }) .catch(function (err) { // Rollback: re-insert the row if we removed it. if (li && parentEl) { if (nextEl) { parentEl.insertBefore(li, nextEl); } else { parentEl.appendChild(li); } } btn.disabled = false; self.showStatus(err && err.message ? err.message : self.t('modFailed', 'Moderation action failed.'), 'error'); }); }; Board.prototype.handleStatusChange = function (featureId, status, sel) { var self = this; if (!featureId || !status) return; sel.disabled = true; this.postWithToken('moderate\_status', { feature\_id: featureId, status: status }) .then(function () { self.refresh(); var label = (self.cfg.statusLabels && self.cfg.statusLabels\[status\]) ? self.cfg.statusLabels\[status\] : status; self.showStatus(self.tf('statusSet', 'Status: %s', label), 'success'); setTimeout(function () { self.hideStatus(); }, 3000); }) .catch(function (err) { sel.disabled = false; self.showStatus(err && err.message ? err.message : self.t('statusFailed', 'Could not set status.'), 'error'); }); }; /\*\* \* Toggle the hidden-features panel open/closed. First open triggers \* an AJAX fetch; subsequent toggles just hide/show the cached list. \*/ Board.prototype.toggleHiddenPanel = function () { if (!this.elHiddenList || !this.elHiddenLabel) return; var arrow = this.elHiddenToggle && this.elHiddenToggle.querySelector('.yc-fb-hidden-arrow'); if (this.hiddenOpen) { this.hiddenOpen = false; this.elHiddenList.hidden = true; this.elHiddenLabel.textContent = this.t('showHidden', 'Show hidden features'); if (arrow) arrow.classList.remove('yc-open'); return; } this.hiddenOpen = true; this.elHiddenList.hidden = false; this.elHiddenLabel.textContent = this.t('hideHidden', 'Hide hidden features'); if (arrow) arrow.classList.add('yc-open'); if (!this.hiddenLoaded) { this.fetchHiddenFeatures(); } }; /\*\* \* Fetch the hidden-features list via the moderator-only endpoint. \* Re-callable to refresh the list after a restore. \*/ Board.prototype.fetchHiddenFeatures = function () { var self = this; if (!this.elHiddenList) return; this.elHiddenList.innerHTML = '2. ' + escapeHtml(this.t('loading', 'Loading...')) + '
'; var url = this.cfg.ajaxUrl + '&task=moderate\_list\_hidden&board\_id=' + encodeURIComponent(this.cfg.boardId); fetch(url, { credentials: 'same-origin', headers: { 'Accept': 'application/json' } }) .then(function (r) { return r.json(); }) .then(function (data) { var payload = self.unwrapAjax(data); if (!payload || payload.ok !== true) { self.elHiddenList.innerHTML = '4. ' + escapeHtml((payload && payload.error) ? payload.error : self.t('hiddenLoadFailed', 'Failed to load hidden features.')) + '
'; return; } self.hiddenLoaded = true; var features = payload.features || \[\]; if (features.length === 0) { self.elHiddenList.innerHTML = '6. ' + escapeHtml(self.t('noHidden', 'No hidden features.')) + '
'; return; } var html = ''; for (var i = 0; i ' + escapeHtml(f.description).replace(/\\n/g, '
') + '' : ''; var restoreTitle = escapeHtml(self.t('restoreTitle', 'Restore this feature')); html += '9. ' + '' + '##### ' + escapeHtml(f.title) + '

    ' + descHtml + '' + escapeHtml(self.tf('votesMeta', '%s votes', f.votes | 0)) + '' + '

    ' + '' + '
'; } self.elHiddenList.innerHTML = html; }) .catch(function () { self.elHiddenList.innerHTML = '11. ' + escapeHtml(self.t('hiddenNetwork', 'Network error while loading hidden features.')) + '
'; }); }; function initAll(scope) { var roots = (scope || document).querySelectorAll('.yc-fb-root'); for (var i = 0; i ---

##  Changelog

---

 [ v0.9.11 09/09/2026 ](#) Changed- The hint in an empty popup, the note on the Content tab and the descriptions of Alert header and Message now describe the real route (New Layout under Builder, then the + in the row), in all six languages; WordPress translations regenerated.

 Fixed- Adding content inside a HootBox now works from the builder interface. The Content tab opens with a Builder section, exactly like the Sublayout element of YOOtheme: click New Layout to put a row in the popup, click the + in that row to add any element, or pick a ready-made layout from the Library. The element was already declared as a sublayout container, but the panel field that opens the nested builder was missing, so the plus below HootBox in the layout tree could only add a neighbour. Popups built earlier keep working: the renderer accepts rows as well as single elements as children.

 [ v0.9.10 08/09/2026 ](#) Changed- The element icon is now #B13DD2.

- Adding an element inside a HootBox does not work from the builder interface. The plus below the element in the builder panel adds an element NEXT to the popup, not inside it, so the instruction in the panel is wrong. The layout format and the renderer handle children correctly; it is the builder interface that offers no way in. Under investigation.

 [ v0.9.9 08/09/2026 ](#) Added- Preview as popup. While editing, the popup sits inline in the page so you can build its content. The badge above it now has a button that opens the popup the way visitors see it: overlay, animation, position, phone layout. Close it and everything is back inline. A preview never counts as a view, so a popup set to "once per visitor" still shows on the live site.

- A screen reader is told when a popup closes by itself. A modal popup carries the sentence in its description, a bar or corner panel announces it once through the live region. The ticking countdown itself stays hidden from screen readers.

 Changed- Finding the popup content. The content is a sublayout: hover over HootBox in the builder panel and click the + that appears below it, or drag an element onto it. That is now said in three places: the hint in the empty popup, the first group of the Content tab, and the descriptions of Alert header and Message. The hint is also easier to read (contrast 4.6:1 instead of 2.8:1).
- The element icon is now 30 by 30 in the element library and 20 by 20 in the page builder, the same sizes YOOtheme uses for its own elements, in the HootBox colour #ac0b0a. It was 24 by 24 in an orange that another YOOzeCase product already uses.
- The badge above the inline popup is visible on dark sections too (its border follows the text colour), and the badge only appears while editing, not when "Always inline" is used on a live test page.
- Three new front-end strings (preview button, content hint, auto-close sentence) in all six languages, WordPress translations regenerated.

 Fixed- Headings placed inside the popup were invisible on themes with light headings (dark sites): white on a white card, contrast 1:1. Headings inside the popup now take the colour of the card, unless they carry an explicit colour class of their own.
- The settings panel had seven tabs. At the default panel width they wrapped to a second line and "Advanced" fell over the first group title. There are six tabs now: the schedule (period, recurring) lives under Triggers, because a schedule is about when the popup opens.

 [ v0.9.8 08/09/2026 ](#) Fixed- Weekdays and the daily time window fell back to the visitor's own clock on sites whose time zone is set as a UTC offset instead of a city. WordPress reports such a site as "+02:00", which the browser's Intl does not accept as a time zone. The offset now travels with the popup as a number of minutes, so the window is still judged by the clock of the site. A fixed offset has no daylight saving, so it stays correct on a cached page as well.

 [ v0.9.7 08/09/2026 ](#) Changed- The element icon in the builder is now the HootBox owl, an original drawing in the same stroke style as the other icons. Recorded in NOTICE.txt.

- WordPress: the eight front-end strings now ship as real translations (Dutch, German, French, Spanish, Italian) instead of English only. They are generated from the Joomla language files with scripts/build-wp-languages.py, so both platforms always say the same thing.

 Fixed- Weekdays and the daily time window were decided on the server only. On a site with page caching the popup kept showing outside its window, and on a page that was cached outside the window it never came back. Those two settings recur, so the popup now stays in the page and the browser checks them again in the time zone of the site, daylight saving included. The from and to dates still decide on the server: that boundary is crossed once, and the popup should not be in the page before it starts. A click on a trigger link respects the window too.
- Bars and corner panels without an overlay deliberately do not take the keyboard focus, so a screen reader never noticed them. They now carry the role of a region named after the title, and their text is announced once through a live region. Centred modals are unchanged: they take focus and announce themselves that way.

 [ v0.9.6 07/09/2026 ](#) Changed- Inline help. Every setting of the HootBox element now carries a full description in the builder: what it does on the site, what each option does, the default and why, when to change it, and the pitfalls. 48 settings were empty or too short; 73 of the 78 settings are now documented. The remaining five are the standard Advanced fields of YOOtheme Pro itself. This text is also the source for the user manual, so the manual can be written without inventing anything.

 [ v0.9.5 07/09/2026 ](#) Fixed- The popup title was invisible on themes that give headings the same colour as the card background. On a white card the contrast was 1:1. The title now takes the text colour of the popup itself.

- Visitors could see the builder hint "Put any element in here: text, images, forms, buttons, video." A popup without content of its own showed that line on the live site. The hint now only appears in the builder.
- The popup stopped halfway through its opening animation and stayed at 90 percent of its size. Everything inside it shrank along, so the close button measured 40 by 40 pixels instead of the 44 by 44 tap target. Two causes: the card style of the theme overruled the popup transition, and the opening animation could stay stuck on its first frame. Both are handled now, so the popup always reaches its full size.

 [ v0.9.4 07/09/2026 ](#) Changed- Inline help for "When an element comes into view" and "Escape key" updated to the new behaviour.

 Fixed- A popup that is hidden on the current device (phone layout "Do not show", or desktop-only on a phone) could still be opened by a link, a data attribute or a click selector. The dialog opened invisibly as a modal and froze the page. Manual opens now respect the device rules and fire a yc-hb:blocked event instead.
- Bars, corner panels and the phone bottom bar (popups without an overlay) were clipped or misplaced inside a section with overflow hidden or a transform. The popup wrapper now moves to the end of body on the live site, so every layout is positioned against the screen.
- "When an element comes into view" never fired on elements taller than about four screens (the observer required 25 percent visibility). It now fires when the element is one fifth into the screen and observes every element the selector matches.
- "Maximum views per visitor" had no effect with frequency "Every page load". The counter is now kept whenever a maximum is set.
- The Escape key now also closes bars and corner panels (popups without an overlay); only the topmost open popup reacts.
- When a manually opened popup replaced an automatic one, the page scroll was unblocked while the new popup was still open.
- Queue: when the next popup in line was no longer allowed, the ones behind it were skipped.
- Countdown pause listeners were bound again on every open; they are now cleaned up on close.
- Accessibility: the dialog name (aria-labelledby) pointed to nothing when the alert header was off but a title was filled in.

 Security- Joomla: the license\_status AJAX task now requires the same administrator permission as activate and deactivate. It returned the instance id and expiry date to anyone.

 [ v0.9.3 05/09/2026 ](#) Fixed- Joomla 5.4: the plugin configuration page gave a 500. Joomla 5.4 added a public render() method to FormField and the licence field declared a private one; renamed to buildLicenseField(); renderField() is also a public FormField method, so the name must not collide with anything in FormField. Compile errors like this cannot be caught, so the try/catch guard did not help.

 [ v0.9.2 05/09/2026 ](#) Fixed- Joomla: stylesheet and script were not loaded on the front end or in the customizer (the relative HTMLHelper path resolved to nothing). Assets now load through the WebAssetManager with an absolute media URL, the same route Epic Slider uses.

## Schema

```json
{
    "@context": "https://schema.org",
    "@type": "Organization",
    "@id": "https://www.yoozecase.com/#organization",
    "name": "YOOzeCase",
    "alternateName": "A YOOzeCase Company",
    "description": "Premium plugins, extensions and YOOtheme Pro elements for WordPress and Joomla. A YOOzeCase Company: polished tools built for usability and performance.",
    "email": "info@yoozecase.com",
    "url": "https://www.yoozecase.com",
    "foundingDate": "2026-01-01",
    "logo": "https://www.yoozecase.com/images/yoozecase/Yoozecase logo.png",
    "image": "https://www.yoozecase.com/images/yoozecase/Yoozecase logo.png",
    "address": {
        "@type": "PostalAddress",
        "addressCountry": "NL",
        "addressLocality": "Rotterdam"
    },
    "sameAs": [
        "https://www.facebook.com/yoozecase",
        "https://x.com/yoozecase",
        "https://www.instagram.com/yoozecase",
        "https://www.youtube.com/@yoozecase",
        "https://bsky.app/profile/yoozecase.bsky.social",
        "https://www.threads.com/@yoozecase",
        "https://mastodon.social/@yoozecase",
        "https://www.reddit.com/user/yoozecase"
    ]
}
```

```json
{
    "@context": "https://schema.org",
    "@type": "BreadcrumbList",
    "itemListElement": [
        {
            "@type": "ListItem",
            "position": 1,
            "name": "Home",
            "item": "https://www.yoozecase.com"
        },
        {
            "@type": "ListItem",
            "position": 2,
            "name": "Extensions",
            "item": "https://www.yoozecase.com/extensions"
        },
        {
            "@type": "ListItem",
            "position": 3,
            "name": "Hootbox",
            "item": "https://www.yoozecase.com/"
        }
    ]
}
```
