Size
6.7 KB
Version
1.1.1
Created
Jan 20, 2026
Updated
14 days ago
1// ==UserScript==
2// @name IXL Auto Answer
3// @description Automatically answers IXL questions every 2 seconds using AI
4// @version 1.1.1
5// @match https://*.ixl.com/*
6// @icon https://www.ixl.com/ixl-favicon.png
7// @grant GM.getValue
8// @grant GM.setValue
9// ==/UserScript==
10(function() {
11 'use strict';
12
13 console.log('IXL Auto Answer extension loaded');
14
15 // Debounce function to prevent multiple rapid calls
16 function debounce(func, wait) {
17 let timeout;
18 return function executedFunction(...args) {
19 const later = () => {
20 clearTimeout(timeout);
21 func(...args);
22 };
23 clearTimeout(timeout);
24 timeout = setTimeout(later, wait);
25 };
26 }
27
28 // Function to extract question text from the page
29 function getQuestionText() {
30 try {
31 // Get the instructions
32 const instructionsEl = document.querySelector('.instructions');
33 const instructions = instructionsEl ? instructionsEl.textContent.trim() : '';
34
35 // Get the passage/question content
36 const passageEl = document.querySelector('.fimc-passage, .qreactbridge');
37 const passage = passageEl ? passageEl.textContent.trim() : '';
38
39 return `${instructions}\n\n${passage}`;
40 } catch (error) {
41 console.error('Error extracting question:', error);
42 return '';
43 }
44 }
45
46 // Function to get all answer choices
47 function getAnswerChoices() {
48 try {
49 const choices = [];
50 const tiles = document.querySelectorAll('.SelectableTile[role="radio"]');
51
52 console.log('Found tiles:', tiles.length);
53
54 tiles.forEach((tile, index) => {
55 const text = tile.textContent.trim();
56 if (text) {
57 choices.push({
58 index: index,
59 text: text,
60 element: tile
61 });
62 }
63 });
64
65 console.log('Extracted choices:', choices.length);
66 return choices;
67 } catch (error) {
68 console.error('Error extracting answer choices:', error);
69 return [];
70 }
71 }
72
73 // Function to select an answer
74 function selectAnswer(answerElement) {
75 try {
76 console.log('Selecting answer:', answerElement.textContent.trim());
77 answerElement.click();
78 return true;
79 } catch (error) {
80 console.error('Error selecting answer:', error);
81 return false;
82 }
83 }
84
85 // Function to submit the answer
86 function submitAnswer() {
87 try {
88 const submitButton = document.querySelector('button.crisp-button');
89 if (submitButton) {
90 console.log('Submitting answer...');
91 submitButton.click();
92 return true;
93 }
94 return false;
95 } catch (error) {
96 console.error('Error submitting answer:', error);
97 return false;
98 }
99 }
100
101 // Main function to answer the question using AI
102 async function answerQuestion() {
103 try {
104 console.log('Starting auto-answer process...');
105
106 // Check if there are answer choices available
107 const choices = getAnswerChoices();
108 if (choices.length === 0) {
109 console.log('No answer choices found');
110 return;
111 }
112
113 // Check if there's a submit button
114 const submitButton = document.querySelector('button.crisp-button');
115 if (!submitButton) {
116 console.log('No submit button found');
117 return;
118 }
119
120 // Get question text
121 const questionText = getQuestionText();
122
123 if (!questionText || choices.length === 0) {
124 console.log('Could not extract question or choices');
125 return;
126 }
127
128 console.log('Question:', questionText);
129 console.log('Choices:', choices.map(c => c.text));
130
131 // Build prompt for AI
132 const choicesText = choices.map((c, i) => `${i + 1}. ${c.text}`).join('\n');
133 const prompt = `You are helping answer an IXL question. Read the question carefully and select the best answer.
134
135Question:
136${questionText}
137
138Answer Choices:
139${choicesText}
140
141Which answer choice is correct? Respond with ONLY the number (1, 2, 3, etc.) of the correct answer.`;
142
143 // Call AI to get the answer
144 console.log('Asking AI for the answer...');
145 const aiResponse = await RM.aiCall(prompt, {
146 type: 'json_schema',
147 json_schema: {
148 name: 'answer_selection',
149 schema: {
150 type: 'object',
151 properties: {
152 answerNumber: {
153 type: 'number',
154 description: 'The number of the correct answer choice (1-based index)'
155 },
156 reasoning: {
157 type: 'string',
158 description: 'Brief explanation of why this is the correct answer'
159 }
160 },
161 required: ['answerNumber']
162 }
163 }
164 });
165
166 console.log('AI Response:', aiResponse);
167
168 // Select the answer (convert from 1-based to 0-based index)
169 const selectedIndex = aiResponse.answerNumber - 1;
170 if (selectedIndex >= 0 && selectedIndex < choices.length) {
171 const success = selectAnswer(choices[selectedIndex].element);
172
173 if (success) {
174 // Wait a moment for the selection to register, then submit
175 setTimeout(() => {
176 submitAnswer();
177 }, 500);
178 }
179 } else {
180 console.error('Invalid answer index from AI:', aiResponse.answerNumber);
181 }
182
183 } catch (error) {
184 console.error('Error in answerQuestion:', error);
185 }
186 }
187
188 // Initialize the auto-answer system
189 function init() {
190 console.log('Initializing IXL Auto Answer...');
191
192 // Start answering questions every 2 seconds
193 setInterval(() => {
194 answerQuestion();
195 }, 2000);
196
197 console.log('Auto-answer system started - will attempt to answer every 2 seconds');
198 }
199
200 // Wait for page to be ready
201 if (document.readyState === 'loading') {
202 document.addEventListener('DOMContentLoaded', init);
203 } else {
204 init();
205 }
206
207})();