The Ferndesk SDK is a lightweight JavaScript library that provides programmatic control over the Self-Service Widget. Once embedded, it exposes a global Ferndesk object on window.Ferndesk that allows you to initialize the widget, open articles, trigger searches, and manage visibility, all from your site's JavaScript code.
Getting started
Installation
First, embed the Ferndesk SDK script in your HTML (or copy from the Ferndesk dashboard):
<!-- Step #1. Install the Ferndesk SDK -->
<script>
    !(function (e, t) {
        var n = 'ferndesk-sdk',
            r = e.FERNDESK_SDK_SRC || 'https://static.ferndesk.com/dist/sdk.js',
            c = 'Ferndesk',
            s = t.currentScript;
        function a() {
            if (!t.getElementById(n)) {
                var e = t.createElement('script');
                ((e.id = n),
                    (e.src = r),
                    (e.async = !0),
                    s && s.nonce && ((e.nonce = s.nonce), e.setAttribute('nonce', s.nonce)));
                var c = t.getElementsByTagName('script')[0];
                c.parentNode.insertBefore(e, c);
            }
        }
        if ('function' != typeof e[c]) {
            var i = [],
                o = function () {
                    i.push(arguments);
                };
            ((o.q = i), (e[c] = o));
        }
        'complete' === t.readyState || 'interactive' === t.readyState
            ? a()
            : t.addEventListener('DOMContentLoaded', a);
    })(window, document);
</script>Initialization
Initialize the widget with your widget ID:
<script>
Ferndesk('init', { widgetId: 'YOUR_WIDGET_ID' })
</script>Once initialized, the widget appears as a floating button on your page, and all SDK methods become available.
The widgetId parameter is required.
Core methods
Init
Initialize the Ferndesk widget.
Ferndesk('init', { widgetId: 'YOUR_WIDGET_ID', open: true })Parameters:
- widgetId(string, required): Your widget ID from the Ferndesk dashboard.
- open(boolean, optional): If true, the widget opens automatically on page load. Default: false.
Returns: None. Triggers widget initialization.
Console errors:
- Ferndesk: init requires a widgetId— widgetId parameter is missing.
- Ferndesk widget failed to load widget configuration— The widget ID is invalid or not found.
Hide
Hide the widget button and disable interaction.
Ferndesk('hide')Parameters: None.
Returns: None.
Behavior: Hides the widget button and closes any open panels. Users cannot access the widget until show() is called.
Example use case: Hide the widget on pages where help isn't needed:
if (window.location.pathname === '/checkout') {
  Ferndesk('hide');
}Show
Display the widget button and make it interactive.
Ferndesk('show')Parameters: None.
Returns: None.
Behavior: Makes the widget button visible. If already visible, no change occurs.
Example use case: Show the widget after a user performs a certain action:
document.getElementById('help-button').addEventListener('click', () => {
  Ferndesk('show');
});Open
Open the widget help panel programmatically.
Ferndesk('open')Parameters: None.
Returns: None.
Behavior: Opens the main widget panel without navigating to a specific article. Users see the help center home.
Example use case: Open help when a user clicks a "Get Help" button:
document.getElementById('get-help').addEventListener('click', () => {
  Ferndesk('open');
});Close
Close the open widget panel.
Ferndesk('close')Parameters: None.
Returns: None.
Behavior: Closes any open widget panel, sidebar, or modal. The widget button remains visible and clickable.
Destroy
Remove the widget completely and free resources.
Ferndesk('destroy')Parameters: None.
Returns: None.
Behavior: Removes the widget from the page, clears event listeners, and resets state. To use the widget again, call init() with a new widget ID.
Example use case: Clean up the widget on page unload in single-page apps:
window.addEventListener('beforeunload', () => {
  Ferndesk('destroy');
});Content navigation methods
OpenArticle
Open a specific article in the widget.
Ferndesk('openArticle', { shortId: 'help-123', presentation: 'widget' })Parameters:
- shortId(string, required): The last part of the article's.
- presentation(string, optional): How to display the article. Options:- 'widget'(default),- 'sidebar',- 'modal',- 'inline'.
- anchor(HTML element, optional): Required for- 'inline'presentation. The element to anchor the article near.
Returns: None.
Presentation modes:
- widget(default): Article opens inside the main help widget.
- sidebar: Article slides in from the right edge as a side panel.
- modal: Article opens in a centered full-screen overlay.
- inline: Article expands near the anchor element (requires- anchorparameter).
Example — Open article in modal on button click:
document.getElementById('faq-button').addEventListener('click', () => {
  Ferndesk('openArticle', { shortId: 'faq-pricing', presentation: 'modal' });
});Example — Open article inline next to an element:
const anchorElement = document.getElementById('billing-info');
Ferndesk('openArticle', {
  shortId: 'billing-faq',
  presentation: 'inline',
  anchor: anchorElement
});Console errors:
- Ferndesk: openArticle requires a shortId— shortId is missing.
- Ferndesk: Inline floating article requires an anchor element—- presentation: 'inline'but no anchor provided.
- Ferndesk: openArticle ignored because the widget has not been initialised—- init()hasn't been called yet.
OpenCollection
Open a specific collection in the widget.
Ferndesk('openCollection', { shortId: 'getting-started' })Parameters:
- shortId(string, required): The collection's short ID from your help center.
Returns: None.
Behavior: Opens the collection inside the widget help panel, displaying all articles in that collection.
Example — Browse troubleshooting articles:
Ferndesk('openCollection', { shortId: 'xFqsqw' });Search
Populate the widget search and display results.
Ferndesk('search', { query: 'billing issues' })Parameters:
- query(string, required): The search query. Must be non-empty.
Returns: None.
Behavior: Opens the widget and displays search results matching the query. If no results match, displays "No results found."
Example — Search when user presses a key combination:
document.addEventListener('keydown', (e) => {
  if (e.key === '?' && e.ctrlKey) {
    Ferndesk('search', { query: 'download videos' });
  }
});Console errors:
- Ferndesk: search requires a non-empty query— query parameter is empty or missing.
Data attributes for inline triggers
In addition to SDK methods, you can use HTML data attributes to trigger widget actions without JavaScript:
data-ferndesk-article
Open an article in widget mode when clicked.
<button data-ferndesk-article="help-123">Learn More</button>Clicking this button opens the article with ID "help-123" in the main widget panel.
data-ferndesk-article-modal
Open an article in modal mode when clicked.
<a href="#" data-ferndesk-article-modal="pricing-faq">View Pricing FAQs</a>Clicking this link opens the article in a centered modal overlay.
data-ferndesk-article-sidebar
Open an article in sidebar mode when clicked.
<button data-ferndesk-article-sidebar="troubleshooting">Troubleshoot</button>Clicking opens the article in a slide-in sidebar.
data-ferndesk-article-inline
Open an article in inline mode anchored to the clicked element.
<button id="my-button" data-ferndesk-article-inline="quick-help">Quick Help</button>Clicking this button opens the article inline near the button. If no anchor is found, the browser console warns and falls back to modal mode.
Error handling and logging
The SDK logs errors and warnings to the browser console (not shown to end-users). Common messages include:
| Message | Cause | Solution | 
|---|---|---|
| 
 | Missing widgetId parameter | Provide your widget ID in the init call | 
| 
 | Invalid or expired widget ID | Verify the ID in the dashboard; regenerate if needed | 
| 
 | SDK script didn't load (blocked by ad blocker, CSP, etc.) | Check network requests; whitelist Ferndesk domain in CSP | 
| 
 | Empty or missing search query | Provide a non-empty string for the query parameter | 
| 
 | Using inline presentation without anchor | Provide an HTML element in the anchor parameter | 
| 
 | Called a method before init() completed | Ensure init() is called before other methods (or wait for SDK load) | 
| 
 | Called a non-existent method | Check the method name and spelling against the SDK reference | 
Content Security Policy (CSP) compliance
If your site uses a strict Content Security Policy, you may need to allowlist the Ferndesk domain:
Example CSP header:
script-src 'self' https://static.ferndesk.com;If the SDK script is blocked by CSP, the console logs a CSP violation error. Add https://static.ferndesk.com to your script-src directive to allow it.
Performance considerations
The SDK uses asynchronous loading to avoid blocking page rendering. Typical load time is 200-500ms on a standard connection.
- Async loading: The SDK script loads asynchronously in the background. Your page continues loading while the SDK initializes. 
- Shadow DOM isolation: The widget uses shadow DOM to encapsulate styles and prevent conflicts with your site's CSS. 
- Lazy content loading: Articles and search results load on demand, not all at once. 
- No performance impact: The SDK adds minimal overhead, typically less than 50KB of JavaScript. 
Examples
Basic setup
<html>
  <body>
    <!-- Your page content -->
    
    <script src="https://static.ferndesk.com/dist/sdk.js"></script>
    <script>
      Ferndesk('init', { widgetId: 'your-widget-id' });
    </script>
  </body>
</html>Open article on button click
<button id="help-btn">Get Help</button>
<script>
Ferndesk('init', { widgetId: 'your-widget-id' });
document.getElementById('help-btn').addEventListener('click', () => {
  Ferndesk('openArticle', {
    shortId: 'faq-overview',
    presentation: 'modal'
  });
});
</script>Search on user input
<input id="search-input" type="text" placeholder="Search help..."/>
<script>
Ferndesk('init', { widgetId: 'your-widget-id' });
document.getElementById('search-input').addEventListener('keypress', (e) => {
  if (e.key === 'Enter') {
    Ferndesk('search', { query: e.target.value });
  }
});
</script>Context-aware help in a React app
import { useEffect, useState } from 'react';
export default function App() {
  const [currentPage, setCurrentPage] = useState('home');
  useEffect(() => {
    // Initialize SDK
    const script = document.createElement('script');
    script.src = 'https://static.ferndesk.com/dist/sdk.js';
    script.async = true;
    document.body.appendChild(script);
    script.onload = () => {
      window.Ferndesk('init', { widgetId: 'your-widget-id' });
    };
  }, []);
  useEffect(() => {
    // Hide widget on checkout page, show elsewhere
    if (currentPage === 'checkout') {
      window.Ferndesk('hide');
    } else {
      window.Ferndesk('show');
    }
  }, [currentPage]);
  return (
    <div>
      {/* Your page content */}
    </div>
  );
}What's next
- Learn how to embed the Self-Service Widget on your site. 
- Review the Self-Service Widget Overview for feature details. 
