Custom filter for deal board view not persisting after page refresh

Created custom filters for our deal board that let reps quickly view high-priority opportunities. The filters work great within a session, but every time users refresh the page or come back later, the filters reset to default. This is killing user efficiency since reps have to reconfigure their view every single time.

We’re storing the filter state but it’s not persisting:

function applyCustomFilter(criteria) {
  localStorage.setItem('dealBoardFilter', JSON.stringify(criteria));
  updateBoardView(criteria);
}

The localStorage saves the data but when the page reloads, the deal board doesn’t restore the custom filter. Need help with proper filter state persistence and handling the dynamic DOM updates that deal board uses.

I’ve implemented persistent custom filters across multiple HubSpot installations. Let me address all three critical components: filter state persistence, localStorage usage best practices, and MutationObserver implementation for dynamic DOM handling.

Filter State Persistence: Your code saves the filter but doesn’t restore it on page load. The deal board loads asynchronously, so you need a complete persistence cycle:

// Save filter state
function saveFilterState(criteria) {
  const filterState = {
    criteria: criteria,
    timestamp: Date.now(),
    boardView: getCurrentBoardView()
  };
  localStorage.setItem('hs_custom_deal_filter', JSON.stringify(filterState));
}

// Restore filter state
function restoreFilterState() {
  const saved = localStorage.getItem('hs_custom_deal_filter');
  if (saved) {
    const state = JSON.parse(saved);
    // Check if saved state is recent (within 7 days)
    if (Date.now() - state.timestamp < 7 * 24 * 60 * 60 * 1000) {
      return state.criteria;
    }
  }
  return null;
}

localStorage Usage: Use a namespaced key to avoid conflicts with HubSpot’s own storage. Add version tracking so you can invalidate old filter formats if your criteria structure changes:

const FILTER_VERSION = '1.0';
const STORAGE_KEY = 'hs_custom_deal_filter_v' + FILTER_VERSION;

Store minimal data. Don’t save the entire board state, just the filter criteria that can reconstruct the view. This prevents quota issues and improves performance.

MutationObserver for Dynamic DOM: The deal board renders progressively. You must wait for complete initialization before applying filters:

function initializeFilterPersistence() {
  const savedFilter = restoreFilterState();
  if (!savedFilter) return;

  const observer = new MutationObserver((mutations, obs) => {
    const dealBoard = document.querySelector('.deal-board-wrapper');
    const dealsLoaded = document.querySelectorAll('.deal-card').length > 0;

    if (dealBoard && dealsLoaded) {
      obs.disconnect();
      setTimeout(() => applyCustomFilter(savedFilter), 500);
    }
  });

  observer.observe(document.body, {
    childList: true,
    subtree: true
  });

  // Fallback timeout if MutationObserver doesn't detect the board
  setTimeout(() => observer.disconnect(), 10000);
}

window.addEventListener('load', initializeFilterPersistence);

The 500ms delay after disconnecting the observer is crucial. The deal board might be present in the DOM but still initializing its internal state. Applying filters immediately can cause them to be overridden.

For user efficiency, add visual feedback during filter restoration:

function applyCustomFilter(criteria) {
  showFilterRestoreIndicator();

  // Apply filter logic
  updateBoardView(criteria);

  // Save for next session
  saveFilterState(criteria);

  setTimeout(hideFilterRestoreIndicator, 1000);
}

Handle edge cases: user logs out (clear filters), workspace switches (namespace by workspace), and concurrent tabs (use storage events to sync):

window.addEventListener('storage', (e) => {
  if (e.key === STORAGE_KEY && e.newValue !== e.oldValue) {
    const newFilter = JSON.parse(e.newValue);
    applyCustomFilter(newFilter.criteria);
  }
});

Test thoroughly with HubSpot’s own filters active. Some native filter combinations conflict with custom filters. Document which built-in filters work alongside your custom implementation.

This complete solution ensures filters persist reliably across sessions while handling all the timing and DOM readiness challenges of the hs-2022 deal board. Your reps will maintain their custom views indefinitely, significantly improving their workflow efficiency.

Make sure your localStorage key is unique enough that it doesn’t conflict with HubSpot’s own storage. Also check localStorage quota limits - if you’re storing complex filter objects, you might be hitting storage limits in some browsers. Stringify your filter criteria efficiently and consider compressing the data if it’s large.

The deal board in hs-2022 renders asynchronously. Even if you retrieve the filter from localStorage on page load, the board might not be ready yet. You need to wait for the board to fully initialize before applying your saved filter. Use a MutationObserver to detect when the board finishes rendering, then apply your custom filter state.