Nothing stops you from making the CustomEvent-based communication bi-directional, and it can pass data with detail property:
// Page script window.addEventListener('RecieveContent', function(evt) { // do something cool with evt.detail }); var event = new CustomEvent('LoadContent'); window.dispatchEvent(event); // Content script window.addEventListener('LoadContent', function(evt) { content = /* ... */ var event = new CustomEvent('RecieveContent', {detail: content}); window.dispatchEvent(event); }); A more in-depth answer can be found herehere.
However, you should ask yourself whether you even need the page-level script to query for data, since you fully control when it's injected. You can use uni-directional approach after you make sure the code has executed:
// Page script window.addEventListener('RecieveContent', function(evt) { // do something cool with evt.detail }); // Content script jsCode.onload = function() { // This fires after the page script finishes executing content = /* ... */ var event = new CustomEvent('RecieveContent', {detail: content}); window.dispatchEvent(event); } document.querySelector('head').appendChild(jsCode);