I wrote this all last year, so it may not be the best - but I believe it still works.
The Start
Installing Extensions Necessary
Blooket uses React, we will need to install this extension for easy debugging.
Chrome Based = https://chromewebstore.google.com/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi?pli=1
Mozilla Firefox Based = https://addons.mozilla.org/en-US/firefox/addon/react-devtools/?utm_source=addons.mozilla.org&utm_medium=referral&utm_content=search
Creating the Game
Sign Up to Blooket and then go to the discover tab and create a game, let’s just do gold quest for 30 minutes. Once game is created open a new tab with blooket.com/join and then type in the game id and join. Start the game.
Searching
Using the React Developer Tools extension we can go to that tab on the Developer Tools menu (Ctrl + Shift + I)
It should look like this.
Hovering over the elements show where they are, we can hover over “Il” and see it is referencing the question and answers.
Because of this, we should click on “Il” to see its contents.
You will notice in props → question it says “correctAnswers” clearly, that means the answers that are correct. That was easy, wasn’t it? Lets expand that by clicking the arrow.
Let’s remember this and save it for later.
The Code
The Beginning
Let’s start with writing something that finds the component, we will be searching the document and looking for each react component there. it constantly searches through the DOM tree starting from a given element to locate a React component’s instance by looking into React’s owner property. Once it finds the component, it returns the statenode, which contains the component’s state and props.
// find component's state and props
function findReactComponent(rootElement = document.querySelector("body > div")) {
// search through children to find the component
const component = Object.values(rootElement)[1]?.children?.[0]?._owner;
if (component && component.stateNode) {
return component.stateNode;
} else {
const childDiv = rootElement.querySelector(":scope > div");
return findReactComponent(childDiv);
}
}
Now let’s utilize this and get the components state and props.
const { state, props } = findReactComponent();
Searching With Code
To search for the component or components depending on question type that are the correct answers we will be selecting and searching through everything and finding the elements with the class “answerContainer”
const answerContainers = document.querySelectorAll('[class*="answerContainer"]');
If you remember from the “Searching” part of this guide, the correct answers are simply under “correctAnswers”. We will be searching whether or not an answer here contains that state.
const question = state.question || props.client.question;
const correctAnswers = question.correctAnswers;
Updating Based On Value
If an answer is correct we will want to in some way highlight it or make it apparent that its correct. We will setup a loop that does this and constantly searches and updates elements based on whether its right, or wrong.
function updateAnswerContainers() {
// get the elements state and props
const { state, props } = findReactComponent();
if (!state || !props) {
console.log('React component state or props not found.');
return;
}
// find all elements with "answerContainer" as a class
const answerContainers = document.querySelectorAll('[class*="answerContainer"]');
// check if its the correct answer
const question = state.question || props.client.question;
const correctAnswers = question.correctAnswers;
// update bg color if its right or wrong
answerContainers.forEach((answer, index) => {
const answerText = question.answers[index];
if (correctAnswers.includes(answerText)) {
answer.style.backgroundColor = "rgb(0, 255, 0)"
} else {
answer.style.backgroundColor = "rgb(255, 0, 0)";
}
});
}
Making it loop
We will just use a set interval so we can constantly loop this and have it update. The 2nd value (number) is how long in milliseconds it takes to update, we will use 100 for 0.1 seconds.
setInterval(updateAnswerContainers, 100);
Combining the Code
// find component's state and props
function findReactComponent(rootElement = document.querySelector("body > div")) {
// search through children to find the component
const component = Object.values(rootElement)[1]?.children?.[0]?._owner;
if (component && component.stateNode) {
return component.stateNode;
} else {
const childDiv = rootElement.querySelector(":scope > div");
return findReactComponent(childDiv);
}
}
const { state, props } = findReactComponent();
const answerContainers = document.querySelectorAll('[class*="answerContainer"]');
const question = state.question || props.client.question;
const correctAnswers = question.correctAnswers;
function updateAnswerContainers() {
// get the elements state and props
const { state, props } = findReactComponent();
if (!state || !props) {
console.log('React component state or props not found.');
return;
}
// find all elements with "answerContainer" as a class
const answerContainers = document.querySelectorAll('[class*="answerContainer"]');
// check if its the correct answer
const question = state.question || props.client.question;
const correctAnswers = question.correctAnswers;
// update bg color if its right or wrong
answerContainers.forEach((answer, index) => {
const answerText = question.answers[index];
if (correctAnswers.includes(answerText)) {
answer.style.backgroundColor = "rgb(0, 255, 0)";
} else {
answer.style.backgroundColor = "rgb(255, 0, 0)";
}
});
}
setInterval(updateAnswerContainers, 100);
Making An Auto answer to this
To implement an auto answer we will need to add a click event and make it when correct answer detected it dispatches that click event
const event = new MouseEvent('click', {
bubbles: true,
cancelable: true,
view: window
});
answer.dispatchEvent(event);
We can simply add this to the pre-existing code for best functionality.
function findReactComponent(rootElement = document.querySelector("body > div")) {
const component = Object.values(rootElement)[1]?.children?.[0]?._owner;
if (component && component.stateNode) {
return component.stateNode;
} else {
const childDiv = rootElement.querySelector(":scope > div");
return findReactComponent(childDiv);
}
}
const {
state,
props
} = findReactComponent();
const answerContainers = document.querySelectorAll('[class*="answerContainer"]');
const question = state.question || props.client.question;
const correctAnswers = question.correctAnswers;
function updateAnswerContainers()
const {
state,
props
} = findReactComponent();
if (!state || !props) {
console.log('React component state or props not found.');
return;
}
const answerContainers = document.querySelectorAll('[class*="answerContainer"]');
const question = state.question || props.client.question;
const correctAnswers = question.correctAnswers;
answerContainers.forEach((answer, index) => {
const answerText = question.answers[index];
if (correctAnswers.includes(answerText)) {
const event = new MouseEvent('click', {
bubbles: true,
cancelable: true,
view: window
});
answer.dispatchEvent(event);
} else {}
});
}
setInterval(updateAnswerContainers, 1);
I did remove the color functionality because well for this you wont be able to see it. I also made the interval 1 millisecond rather than the pre-existing 100 so it clicks fast enough.
Adding extra features
We can adjust the code for more accessibility, hiding the answers in plain site, or by logging them to console. I will just be making the answers hidden in plain site for my extra feature example. We will be using a border radius of 0 for correct answers → this turns off the corner rounding for it.
answerContainers.forEach((answer, index) => {
const answerText = question.answers[index];
if (correctAnswers.includes(answerText)) {
answer.style.borderRadius = 0;
} else {}
})
We can also add something to console log the correct answer.
answerContainers.forEach((answer, index) => {
const answerText = question.answers[index];
if (correctAnswers.includes(answerText)) {
console.log(answerText);
} else {}
});
Adding something to display chest values
Like answers, chest values are easy to get. In React Developer Tools they will be under “sme” and “choices.” Basically we restructure the answer getting script and make it work with this. I will be removing the image from the chest and replacing it with text.
“findReactComponent” function stays the same. We will be updating “updateAnswerContainers” function.
Let’s first start with checking whether the stage is on prize or not.
// check if the stage is = to prize
if (state.stage !== "prize" && props.client?.stage !== "prize") {
console.log('Component stage is not "prize".');
return;
}
Now we will get the choices array
// get choices array if it exists
const choices = state.choices || props.client.choices;
if (!choices || !Array.isArray(choices)) {
console.log('Choices not found or invalid.');
return;
}
Along with this so we can replace the images from the prizes let’s define a structure of the class names of where the chests are.
// class names to replace with choices
const choiceClassMap = {
'_choice1_azxsv_80': 0,
'_choice2_azxsv_108': 1,
'_choice3_azxsv_136': 2
};
Now we will look over the choices, we will be updating the HTML code to correspond with the values.
Object.keys(choiceClassMap).forEach(className => {
const choiceIndex = choiceClassMap[className];
const choice = choices[choiceIndex];
const container = document.querySelector(`.${className}`);
if (choice && container) {
container.innerHTML = '';
const text = `${choice.type}: ${choice.text}`;
container.textContent = text;
} else {
console.error(`Choice ${choiceIndex} or container with class "${className}" not found.`);
}
});
Full Revised Code For Choice Previews
function findReactComponent(rootElement = document.querySelector("body > div")) {
const component = Object.values(rootElement)[1]?.children?.[0]?._owner;
if (component && component.stateNode) {
return component.stateNode;
} else {
const childDiv = rootElement.querySelector(":scope > div");
return findReactComponent(childDiv);
}
}
function updateAnswerContainers() {
const { state, props } = findReactComponent();
if (!state || !props) {
console.log('React component state or props not found.');
return;
}
if (state.stage !== "prize" && props.client?.stage !== "prize") {
console.log('Component stage is not "prize".');
return;
}
const choices = state.choices || props.client.choices;
if (!choices || !Array.isArray(choices)) {
console.log('Choices not found or invalid.');
return;
}
const choiceClassMap = {
'_choice1_azxsv_80': 0,
'_choice2_azxsv_108': 1,
'_choice3_azxsv_136': 2
};
Object.keys(choiceClassMap).forEach(className => {
const choiceIndex = choiceClassMap[className];
const choice = choices[choiceIndex];
const container = document.querySelector(`.${className}`);
if (choice && container) {
container.innerHTML = '';
const text = `${choice.type}: ${choice.text}`;
container.textContent = text;
} else {
console.error(`Choice ${choiceIndex} or container with class "${className}" not found.`);
}
});
}
setInterval(updateAnswerContainers, 100);
Creating An Always Correct Part
Basically we will be adding all question to correctAnswers, it is super simple and should be super small code.
Let’s go ahead and add a function for this;
function updateCorrectAnswers() {
const component = findReactComponent();
if (!component) {
console.log('React component not found.');
return;
}
const { state, props } = component;
if (!state || !props) {
console.log('React component state or props not found.');
return;
}
// chgeck if stage = question
const stage = state.stage || props.client?.stage;
if (stage !== "question") {
return;
}
const question = state.question || props.client.question;
const correctAnswers = question.correctAnswers;
const answerContainers = document.querySelectorAll('[class*="answerContainer"]');
answerContainers.forEach((answer, index) => {
const answerText = question.answers[index];
if (answerText && !correctAnswers.includes(answerText)) {
correctAnswers.push(answerText);
// add all answers to correct answers
}
});
console.log('Updated correctAnswers:', correctAnswers);
}
Always Correct Full Code
function findReactComponent(rootElement = document.querySelector("body > div")) {
const component = Object.values(rootElement)[1]?.children?.[0]?._owner;
if (component && component.stateNode) {
return component.stateNode;
} else {
const childDiv = rootElement.querySelector(":scope > div");
return findReactComponent(childDiv);
}
}
function updateCorrectAnswers() {
const component = findReactComponent();
if (!component) {
console.log('React component not found.');
return;
}
const { state, props } = component;
if (!state || !props) {
console.log('React component state or props not found.');
return;
}
const stage = state.stage || props.client?.stage;
if (stage !== "question") {
return;
}
const question = state.question || props.client.question;
const correctAnswers = question.correctAnswers;
const answerContainers = document.querySelectorAll('[class*="answerContainer"]');
answerContainers.forEach((answer, index) => {
const answerText = question.answers[index];
if (answerText && !correctAnswers.includes(answerText)) {
correctAnswers.push(answerText);
}
});
console.log('Updated correctAnswers:', correctAnswers);
}
setInterval(updateCorrectAnswers, 1);
Adding A Gold Editor For Gold Quest
This is super simple, so I again won’t fully explain as it should be understandable enough if you have read this whole blog post.
function findReactComponent(rootElement = document.querySelector("body > div")) {
const component = Object.values(rootElement)[1]?.children?.[0]?._owner;
if (component && component.stateNode) {
return component.stateNode;
} else {
const childDiv = rootElement.querySelector(":scope > div");
return findReactComponent(childDiv);
}
}
function updateGoldValues() {
// amount of gold u want
const goldValue = "999999999999999";
// find component
const component = findReactComponent();
if (!component) {
console.log('React component not found.');
return;
}
const { state, props } = component;
if (!state) {
console.log('React component state not found.');
return;
}
state.gold = goldValue;
state.gold2 = goldValue;
if (props && props.client) {
props.client.gold = goldValue;
props.client.gold2 = goldValue;
} else {
console.log('props.client not found.');
}
}
updateGoldValues();
A quick note for this, after you run it you must answer a question for it to set. For it to show on leader board I believe you must gain or lose any amount of money.
Making An Always Triple / Editing Choices
It will basically be like our choice previews but we manipulate the values like how we do in always correct.
function findReactComponent(rootElement = document.querySelector("body > div")) {
const component = Object.values(rootElement)[1]?.children?.[0]?._owner;
if (component && component.stateNode) {
return component.stateNode;
} else {
const childDiv = rootElement.querySelector(":scope > div");
return findReactComponent(childDiv);
}
}
function updateAllChoices() {
const component = findReactComponent();
if (!component) {
console.log('React component not found.');
return;
}
const { state, props } = component;
if (!state || !props) {
console.log('React component state or props not found.');
return;
}
const choices = state.choices || props.client?.choices;
if (!choices || !Array.isArray(choices)) {
console.log('Choices not found or invalid.');
return;
}
const newChoice = {
type: "multiply",
val: 3,
text: "Triple Gold!",
blook: "Unicorn"
};
choices.forEach((choice, index) => {
choices[index] = newChoice;
});
console.log('Updated choices:', choices);
}
setInterval(updateAllChoices, 100);