Состояние страницы описывается набором закрытых блоков. Понадобится ещё и время их закрытия, чтобы игнорировать устаревшие. Предлагаю хранить объект, где ключи – id блоков. А значения – timestamp когда их закрыли. Что-то типа 
const boxState = {
  "block-ad-123": 1668436835032,
  "block-ad-456": 1668436842279,
};
Хранить этот объект можно в 
localStorage, переведя в строку: 
JSON.stringify(boxState)
Изначально закрытых блоков нет, просто пустой объект. 
Алгоритм
Загрузили страницу, все блоки видны.
Считали состояние из localStorage, и если там пусто, взяли пустой объект.
Пройти по объекту, и если прошло еще мало времени по очередному ключу, скрыть его блок.
Если времени прошло много – удалить этот ключ из стейта.
Если при обходе объекта были удаления – сохранить обновлённый стейт в localStorage.
spoilerconst boxKey = 'BOX_STATE'; // ключ для хранения в localStorage
const boxState = JSON.parse(localStorage.getItem(boxKey)) ?? {};
const TTL = 36e5; // сколько держать блок скрытым, в миллисекундах (1 час)
const expiredIds = [];
Object.entries(boxState)
  .forEach((key, value) => {
    if (value + TTL < Date.now()) {
      // устарел, более не скрываем
      expiredIds.push(key);
    } else {
      // актуален, скрываем блок
      document.getElementById(key).classList.add("hide");
    }
  });
  if (expiredIds.length) {
    expiredIds.forEach(id => delete boxState[id]);
    localStorage.setItem(boxKey, JSON.stringify(boxState));
  }
 
При нажатии на крестик:
	- добавить в стейт id этого блока и текущее время Date.now(),
 
- сохранить состояние в localStorage,
 
- добавить класс блоку.
 
spoilerconst onClose = ({ target }) => {
  const block = target.closest('div.block');
  const { id } = block;
  boxState[id] = Date.now();
  localStorage.setItem(boxKey, JSON.stringify(boxState));
  block.classList.add("hide");
};
document.querySelectorAll('img.x-button')
  .addEventListener('click', onClose);