n8n Tutorial

  • Loading...

n8n tutorial - Lesson 24: Quality Gate Pattern in n8n: AI Review Before Publishing

n8n tutorial - Lesson 24: Quality Gate Pattern in n8n: AI Review Before Publishing

Hi everyone, in this post we're building a Quality Gate inside an n8n Content Factory workflow — an AI-powered review layer that blocks low-quality content before it ever gets published. This is a core pattern in n8n quality control automation and one of the most practical additions you can make to any content pipeline.

How to do:

Step 1 — Design the AI Review Checklist (Blog + YouTube)

Before adding any nodes, define exactly what the AI will check and what counts as a passing score.
  1. For the Blog review, define 5 criteria: word_count, has_headings, has_keyword, no_placeholder, title_length.
  2. For the YouTube review, define 5 criteria: title_length, description_length, has_tags, has_timestamps, no_empty_field.
  3. Set the pass threshold at ≥ 4 out of 5 criteria met.
  4. Require the AI to return a structured JSON object with three fields: pass, score, and notes.

Tip — Locking down the output schema before building the nodes saves debugging time later. The pass field will drive your IF node, score goes to the rejected log, and notes tells you exactly why a piece failed.

Step 2 — Insert AI Review Nodes into Each Child Workflow

Add an AI review node to both the Blog and YouTube child workflows, placing each one at the right point in the chain.
  1. In T6-Content-Child-Blog, insert an AI Review Blog node between the Format HTML node and the POST Draft Blogger node.
  2. In T6-Content-Child-YouTube, insert an AI Review YouTube node at the equivalent position — after content is fully formatted.
  3. In the User message of AI Review YouTube, wrap array fields with JSON.stringify():
    • Tags: JSON.stringify($('YouTube SEO').item.json.output.tags)
    • Timestamps: JSON.stringify($('YouTube SEO').item.json.output.timestamps)

Note — If you pass an array directly into a User message expression without JSON.stringify(), n8n renders it as [object Object] and the AI cannot read the data. Always stringify arrays before injecting them into prompt strings.

Step 3 — Add Structured Output Parsers

Attach a Structured Output Parser to each AI review node so the response always comes back as clean, typed JSON.
  1. For AI Review Blog: use the Schema (JSON string) method in the parser.
  2. For AI Review YouTube: use the Generate From JSON Example method in the parser.
  3. Provide an example JSON like {"pass": true, "score": 4, "notes": "missing keyword"} so n8n infers the correct types.

Note — These two parser methods produce different output types for the pass field. The Schema method returns "true" as a string; the Generate From JSON Example method returns true as a boolean. You must configure the IF node to match the correct type for each workflow.

Step 4 — Add IF Nodes to Route Pass vs. Fail

Insert an IF node after each review node to split the workflow into a passing branch and a failing branch.
  1. In T6-Content-Child-Blog, add an IF node named Check Pass.
  2. Set its condition on $json.pass:
    • Because the Blog parser returns a string, set the condition to String → equals → "true" — not Boolean.
  3. In T6-Content-Child-YouTube, add an IF node named Check Pass YT.
  4. Set its condition to Boolean → is true because the YouTube parser returns a real boolean.
  5. Connect the True branch of each IF node to the existing publish nodes (POST Draft Blogger, Create Google Doc).
  6. Connect the False branch of each IF node to a Google Sheets Append node targeting the Sheet T6-Rejected.

Tip — Mixing up string "true" and boolean true in IF conditions is one of the most common silent bugs in n8n. If your IF node always routes to the False branch despite the AI passing content, this type mismatch is the first thing to check.

Step 5 — Fix Cross-Node References After IF Node Insertion

After inserting the IF node, all downstream nodes lose their direct $json context — this is a critical gotcha in this n8n tutorial.
  1. Understand what changed: after the IF node, $json inside downstream nodes refers to the IF node's output (only the review result), not the original formatted content.
  2. In POST Draft Blogger, replace any $json.xxx references with explicit cross-node refs, for example:
    • $('Format HTML').item.json.title
    • $('Format HTML').item.json.html_content
  3. Apply the same fix to Create Google Doc — reference the correct upstream node by name for every field it needs.
  4. For the YouTube child workflow, confirm that Create Google Doc is placed after the IF node, not before it. An earlier misplacement caused it to run regardless of review outcome.

Note — Cross-node references like $('NodeName').item.json.field are the reliable way to reach data from any earlier node in the chain. Make this your default approach whenever the data path passes through a branching node like IF, Switch, or Merge.

Step 6 — Fix HTML Content in POST Draft Blogger Body

Passing HTML as a raw JSON string in the request body breaks when the content contains special characters.
  1. Identify the problem: html_content contains double quotes and newlines, which corrupt the raw JSON string body.
  2. Switch the POST Draft Blogger node's body mode from Raw JSON string to Body Parameters (key-value pairs).
  3. Map each field (title, content, labels, etc.) as a separate key-value entry — n8n handles escaping automatically in this mode.

Tip — Whenever you're sending HTML or any user-generated text in an HTTP request body, key-value / Body Parameters mode is safer than raw JSON strings. n8n escapes the values for you, eliminating an entire class of encoding bugs.

Step 7 — Set Up the T6-Rejected Sheet Log

Route failed content to a dedicated Google Sheet so you can review and fix it later.
  1. Create a new Google Sheet named T6-Rejected.
  2. Define these columns: timestamp, topic, score, notes.
  3. In the False branch of each IF node, connect a Google Sheets → Append Row node targeting this sheet.
  4. Map the fields:
    • timestamp: {{ $now }}
    • topic: cross-node ref to the topic field from the trigger
    • score: $json.score
    • notes: $json.notes

Step 8 — Pass row_number into Child Workflows and Fix Mark Done

Matching sheet rows by topic string is fragile; switching to row_number makes the Mark Done update reliable.
  1. Open the child workflow's trigger node (When Executed by Another Workflow) and add a new input field: row_number (type: Number).
  2. In the parent workflow (T6-Content-Factory-Dispatch), open the Call Child Blog Workflow node and click Refresh Input List to see the new field.
  3. Map the parent's row_number value into the new field.
  4. In the Mark Done node, change the row-matching logic from topic string to row_number (number match).

Tip — String-based row matching fails silently when there's a whitespace difference or encoding mismatch between the sheet and the workflow variable — you get "No output data returned" with no clear error. Number-based matching with row_number is deterministic and always safe.

Step 9 — Test End-to-End: Pass and Fail Paths

Run a full test covering both branches to confirm the quality gate works correctly.
  1. Trigger the dispatch workflow with a topic that will produce high-quality content (score ≥ 4).
  2. Verify the True branch executes: Blogger draft is posted, Google Doc is created, Sheet status is updated to done.
  3. Temporarily lower the pass threshold or submit a topic with missing fields to force a fail.
  4. Verify the False branch executes: a new row appears in T6-Rejected with correct timestamp, topic, score, and notes.
  5. Confirm Mark Done updates the correct row (matched by row_number, not topic string).

Key Lessons from This Session

  1. Cross-node refs break after IF nodes. Once your data path passes through a branching node, $json no longer points to earlier content — always use $('NodeName').item.json.field explicitly.
  2. HTML in raw JSON bodies causes silent corruption. Switch to Body Parameters (key-value) mode and let n8n handle escaping automatically.
  3. Structured Output Parser type depends on the method used. Schema JSON string → returns pass as a string; Generate From JSON Example → returns pass as a boolean. Your IF condition must match the actual type.
  4. Child workflow inputs require declaration in the trigger first. The parent cannot pass a new field like row_number until the child's trigger node declares it, followed by a Refresh Input List in the parent.
  5. Use row_number, not topic strings, for sheet row matching. String matching fails silently on whitespace or encoding differences; number matching is deterministic.
  6. Always JSON.stringify arrays in prompt expressions. Arrays passed raw into User message expressions render as [object Object], making them unreadable to the AI model.

Conclusion:

In this n8n workflow automation tutorial, we added a full AI-powered quality gate to a Content Factory — covering checklist design, structured output parsing, IF-based routing, rejected content logging, and reliable row matching. These patterns make your automation genuinely production-ready by catching bad content before it ever reaches a live channel. Next session we move into Week 7 and start building our first AI Agent in n8n.

If you have any questions, feel free to leave a comment below. Thank you!

Tags: n8n quality control automation, n8n tutorial, n8n workflow automation, AI review workflow, content factory n8n, structured output parser n8n, quality gate pattern, n8n IF node

Maybe you are interested!

Building Android Apps Directly in Google AI Studio: No Coding Required

Anyone can start building projects, web apps, and mobile applications using Vibe Coding—software development has never been more accessible. Here's the thing: plenty of people have tested and evaluated software extensively, but many lack hands-on experience actually building it. Yet with Google AI Studio, you can create your first functional Android app in less than 30 minutes flat. What's interesting here is that you don't need Android Studio, APK compilation knowledge, or even basic coding skills.

Google AI Studio now supports building Android applications directly in your web browser—you can skip the traditional Android Studio workflow entirely and go straight to deploying APKs. Transform a basic web application concept into a standalone APK that installs locally on all your Android phones and tablets.

Google AI Studio Makes Android Development Genuinely Simple

Programming experience is optional—you won't need to download IDEs like Android Studio

If you've already spent time with AI chatbots like Gemini, you already understand how to use Google AI Studio. Gemini powers this entire experience, bringing the same natural language comprehension you'd find in the dedicated app. Here's how to get started: open AI Studio in your browser (Chrome works best) and click New app from the sidebar. Then select Build an Android app under the Tools section. This tells AI Studio to use Kotlin and the Android SDK to generate a native Android application based on your prompt.

Your prompt can be as simple or detailed as you want. Need inspiration? Click the I'm feeling lucky button to generate a random sample prompt for an Android project—then hit Build to send it to Gemini. Better yet, use these examples as a springboard for a custom prompt that describes exactly what you want your new Android app to do.

One developer loved a web app they'd built months earlier and wanted to recreate it as a native Android application using AI Studio's new capabilities. They crafted this prompt and hit Build:

Build a vinyl discovery app that uses a Discogs web crawler to display album cards for every entry in my collection. Each album card should have a title, artist, album artwork, and any key release notes. Add a shuffle function that selects a random album from my library. Finally, ensure the UI is responsive and optimized for tablet and mobile viewing. Prioritize light mode design.

The initial request wasn't perfect—their first few attempts at creating the Android app didn't go smoothly. The original prompt leaned too heavily on paid APIs requiring keys to access. Since this was a personal project, they needed to eliminate paid services entirely. They refined the prompt to use Gemini and Google AI Studio's built-in web scraping tools to fetch data without API keys. After that adjustment, everything worked as expected.

You might avoid the same API complications, but you'll definitely hit a few snags during the development process. The good news? There are straightforward solutions. Google AI Studio supports conversational prompting. You can preview your Android app as it's being built, test the design, and verify features before deploying to your device. Follow-up prompts tell Gemini and AI Studio exactly what to fix, add, or refine. Sometimes you'll need to start fresh with a completely new prompt to resolve persistent issues.

Another approach: ask Gemini to write the perfect prompt for you. This is called meta prompting—requesting one AI model (Gemini) to create a detailed, optimized prompt for another AI tool (Google AI Studio).

Skip Programming Knowledge and Web Hosting Fees

Compiling an app into an installable APK file is genuinely transformative


Google AI Studio on Motorola Razr Fold

Building web apps with Vibe Coding tools is straightforward, but creating native Android apps traditionally requires significantly more effort. People gravitate toward Vibe Coded applications for personal projects because Google AI Studio packages them neatly into native Android APK files without needing Android Studio at all. The real concern is that this approach makes apps less dependent on cloud servers while eliminating expensive hosting fees. For private applications you're not planning to distribute publicly, installing a Vibe Coded APK from AI Studio beats any cloud-based solution.

However, AI Studio has one limitation—it won't provide a downloadable APK file for distribution. Google's dedicated Android development environment (which handles this feature) is more complex, but it does allow you to download APKs and share them wirelessly across Android devices for quick installation. Instead, Google AI Studio relies on Android Debug Bridge (ADB) and USB debugging to install apps directly on your Android phone or tablet.

To enable USB debugging, open your Settings app and tap About phone. Find your build number or version number in the list and tap it seven times. This activates Developer options, which you'll need for USB debugging. Navigate to Settings → System → Developer options → USB debugging and toggle it on. Then head back to your AI Studio project on your computer.

Note: You need Chrome to install apps on Android devices from Google AI Studio using USB debugging.

From there, click the Install button in the top-right corner of the app preview window in AI Studio. Connect your phone via USB and tap Install via USB. Within seconds, the app installs and launches automatically on your Android device. Seriously, that's it.


Discogs Shuffle app created with Google AI Studio

After roughly 30 minutes building in AI Studio and a few minutes of debugging, you've got a custom Android app. AI Studio does take considerable time to process, but most of that happens in the background without requiring manual intervention. Submit a prompt, let AI Studio work, then return later to refine with another prompt or test and install the finished application.

The experience isn't flawless—experienced developers or those willing to learn might prefer more traditional IDEs—but it absolutely produces a working Android app. The best part about using Vibe Coding tools like Google AI Studio? Creating an Android application that actually solves your specific needs.

Related Articles

Building Interactive Sequencing Activities on Educaplay with AI

Educaplay's Line Up feature is a game-changer for building interactive learning activities powered by artificial intelligence. It lets you design ordering games in minutes—where students drag and drop cards to arrange them in the correct sequence. Just enter your topic or lesson content, and the AI generates complete card sets automatically. What's interesting here is how much friction it removes from the activity creation process.

The standout advantage of Line Up AI is the massive time savings. Instead of manually writing every question and answer pair, AI handles content generation in seconds. You still have full control to add more topics afterward if needed. Here's how to build your first interactive sequencing game on Educaplay.

How to Create an Interactive Ordering Game on Educaplay

Step 1:

Head to the Educaplay resource editor below and set up your account.

https://www.educaplay.com/resource-editor/

Once you're in, select the Line Up application to start building your game.

You'll see two content creation options: build manually or use AI.

For manual creation, you'll enter all card content yourself and organize each one according to your chosen criteria.

Step 2:

For the AI-powered approach, configure your content settings as shown below.

Enter your topic, then hit Generate to let the system build your ordering cards automatically.

Step 3:

Wait a moment while the system creates your sequencing activity, then click Start to begin playing.

The interactive interface appears as shown. Drag and drop each card following the on-screen instructions. Once you've arranged everything, hit the check button to verify your ordering is correct.

You can add new topics anytime, and Educaplay will automatically generate fresh card sets for sequencing exercises.

Step 4:

Go to My Games in the left sidebar to view all your created activities. Click the three-dot menu next to your Line Up game and select Edit.

From here, you can add additional topics to expand your game and offer more sequencing challenges.

Step 5:

Ready to share? Click the share icon and you'll get a shareable game link to distribute to students.

  • Access the interactive sequencing activity on Educaplay

Related Articles

n8n tutorial - Lesson 23: Production-Ready n8n Workflows: Hardening and Scheduling

n8n tutorial - Lesson 23: Production-Ready n8n Workflows: Hardening and Scheduling

Hi everyone, in this post we're covering how to harden a multi-workflow n8n automation into a true n8n production workflow — adding error handling, scheduling, and live alerting. This is Session 23 of the n8n Workflow Automation Tutorial series, and it's where your Content Factory stops being a manual prototype and starts running reliably on its own.

How to do:

Step 1 — Verify Initial Workflow States

Before making any changes, confirm the starting state of all four workflows to avoid activating them in the wrong order.
  1. Open your n8n dashboard and check that T6-Content-Factory-Dispatch, T6-Content-Child-Blog, and T6-Content-Child-YouTube are all Inactive.
  2. Confirm that T6-B1-Error-Handler is already Active. This is the baseline — the error handler must be live before you test anything.

Note — If any child workflow is Active before you configure its error settings, deactivate it now. You want a clean slate before touching the node settings.

Step 2 — Set "On Error = Continue (using error output)" on Execute Sub-workflow Nodes

This setting prevents a child workflow failure from silently killing the entire parent run — it routes the error into a visible output instead.
  1. Open T6-Content-Factory-Dispatch (the parent workflow) in the editor.
  2. Click the Execute Sub-workflow node that calls T6-Content-Child-Blog.
  3. Go to Settings inside that node and find the On Error dropdown. Set it to Continue (using error output).
  4. Repeat the same three actions for the Execute Sub-workflow node that calls T6-Content-Child-YouTube.
  5. Save the parent workflow after both nodes are configured.

Tip — After selecting Continue (using error output), you will notice a new red output pin appears on the Execute Sub-workflow node. This is expected behavior — it is the error branch. You do not need to connect it to anything right now; it simply means errors will no longer crash the execution silently.

Step 3 — Replace Manual Trigger with a Schedule Trigger

Swapping out the Manual Trigger for a Schedule Trigger is what makes this an automated n8n production workflow instead of a tool you run by hand.
  1. Inside T6-Content-Factory-Dispatch, click the existing Manual Trigger node and delete it.
  2. Add a new Schedule Trigger node from the node panel.
  3. Configure it with the following values:
    • Trigger Interval: Days
    • Hour: 8
    • Minute: 0
  4. Connect the output of Schedule Trigger to the first node in your existing flow (the same connection the Manual Trigger had).
  5. Save the workflow.

Step 4 — Attach the Error Workflow to All Three Workflows

Assigning T6-B1-Error-Handler as the error workflow for each of the three workflows ensures that any unhandled failure fires a Telegram alert automatically.
  1. Open T6-Content-Factory-Dispatch and go to Workflow Settings (the gear icon or top menu).
  2. Find the Error Workflow field and select T6-B1-Error-Handler from the dropdown. Save.
  3. Open T6-Content-Child-Blog, go to Workflow Settings, set Error Workflow to T6-B1-Error-Handler. Save.
  4. Open T6-Content-Child-YouTube, go to Workflow Settings, set Error Workflow to T6-B1-Error-Handler. Save.

Note — The Error Workflow field only accepts workflows that are already Active. Since you verified T6-B1-Error-Handler is Active in Step 1, it will appear in the dropdown without issues.

Step 5 — Activate All Three Workflows in the Correct Order

n8n enforces a strict activation order: child workflows must be Active before the parent, or you will get a not published error when activating the parent.
  1. Activate T6-Content-Child-Blog first — toggle it to Active and confirm the status turns green.
  2. Activate T6-Content-Child-YouTube second — same process.
  3. Activate T6-Content-Factory-Dispatch last — only after both children are confirmed Active.

Production tip — Always follow the child-before-parent activation order whenever you deactivate and reactivate these workflows later. Forgetting this is the most common reason for the not published error in multi-workflow n8n setups.

Step 6 — Run a Clean Production Test

Test the live production execution path (not the UI test button) to confirm everything runs without errors.
  1. Inside T6-Content-Factory-Dispatch (which is now Active), click Execute once to trigger a production-mode run.
  2. Go to the Executions tab and confirm all runs show a Success status.
  3. Check your Telegram channel — if there are no workflow errors, no alert message should arrive. Silence here is correct behavior.

Tip — The UI test button (the flask/beaker icon) does not trigger the Error Workflow even if an error occurs. Only executions running from an Active workflow trigger the Error Handler. Always use Execute once from an Active workflow when you want to test production error alerting.

Step 7 — Inject a Fake Error to Verify Telegram Alerting

Deliberately breaking one child workflow confirms that your error alerting pipeline actually works end-to-end.
  1. Open T6-Content-Child-Blog and locate the HTTP Request node that calls your content endpoint.
  2. Change its URL to an intentionally wrong value (for example, add _broken to the end of the URL).
  3. Save T6-Content-Child-Blog — it remains Active with the bad URL.
  4. Go back to T6-Content-Factory-Dispatch and click Execute once again.
  5. Check Telegram — you should receive an error alert from T6-B1-Error-Handler within seconds. ✅
  6. Go back to T6-Content-Child-Blog, restore the correct URL, and save.
  7. Run Execute once one more time — confirm executions are clean and no Telegram alert fires.

Step 8 — Deactivate the Parent Workflow Until Needed

After the session, deactivate T6-Content-Factory-Dispatch to prevent it from running automatically at 8:00 AM until you are ready.
  1. Toggle T6-Content-Factory-Dispatch to Inactive on the dashboard.
  2. Leave T6-Content-Child-Blog, T6-Content-Child-YouTube, and T6-B1-Error-Handler as Active.
  3. When you want the schedule to run again, toggle the parent back to Active with one click — no other changes needed.

Note — Keeping the children Active while the parent is Inactive costs nothing and means reactivation later is instant. This is a clean pattern for managing n8n workflow automation schedules you want to pause temporarily.

Key Lessons from This Session

  1. Child workflows must be activated before the parent. n8n throws a not published error if the parent is activated while any child is still Inactive. Order: child Blog → child YouTube → parent Dispatch.
  2. The UI test button does not trigger the Error Workflow. You must run from an Active workflow using Execute once to test real error alerting behavior.
  3. "Continue (using error output)" adds a red output pin — this is normal. The pin is the error branch; you do not need to wire it up immediately, but it makes errors visible instead of swallowing them.
  4. Silence on Telegram after a clean run is the correct behavior. If no errors occur, no alert should fire — confirm this during your clean test run.
  5. Deactivating only the parent is enough to pause the schedule. Children and the error handler can stay Active, making re-enabling the whole system a one-click action.

Conclusion:

In this session of the n8n tutorial series, we transformed a manually-run Content Factory into a hardened n8n production workflow with scheduled execution, multi-level error handling, and live Telegram alerting. The end result is a system where failures surface immediately, the schedule is easy to pause and resume, and every layer — parent and children — is protected by the same error handler. Next up, we'll look at adding a quality gate using an AI review checklist before content gets posted, or extending the pattern with a new Email child workflow.

If you have any questions, feel free to leave a comment below. Thank you!

Tags: n8n production workflow, n8n tutorial, n8n workflow automation, n8n schedule trigger, n8n error handling, n8n execute sub-workflow, n8n content factory, workflow automation tutorial

Maybe you are interested!

Generate Student Assessment Rubrics Instantly with AI on Canva

Creating rubrics from scratch is tedious. That's where Canva's AI Rubric Maker comes in—a smart tool that generates assessment criteria templates in seconds. Instead of manually building evaluation frameworks, teachers can now leverage AI to produce structured grading rubrics based on specific criteria like content quality, technical skills, completion level, and creativity. A rubric itself is a scoring matrix used to grade assignments, projects, presentations, and other student work using predefined standards.

What makes this tool particularly useful is how it combines AI generation with Canva's design capabilities. The AI Rubric Maker generates an initial framework based on your input, then Canva lets you polish it into a visually appealing, printable format ready to share with students before they begin work. This transparency helps students understand exactly what's expected, while giving teachers a consistent evaluation framework. Here's how to set it up.

Step-by-Step Guide: Building Assessment Rubrics on Canva

Step 1: Access the AI Rubric Maker

Open Canva and tap the three-dot menu icon, then select Apps from the dropdown menu.

Type rubric into the search bar. Select the AI Rubric Maker result that appears.

Click on the AI Rubric Maker app to launch it.

You'll see an option to start with a new design or use an existing template. Choose your preference and continue.

Step 2: Configure Your Rubric Parameters

A new panel appears on the left side with input fields for your rubric settings. First, select Vietnamese as your language (or choose your preferred language for output).

Now fill in the remaining fields. For example, if you're grading student presentations, you'd add:

Learning Standards/Objectives:

Students will demonstrate the ability to construct and deliver clear presentations with accurate content, appropriate visual aids, and effective communication skills before an audience.

Task Description:

Students prepare a presentation on an assigned topic. The presentation must include an introduction, main content, conclusion, and relevant images or examples. Students should demonstrate presentation skills, explain concepts clearly, and answer questions from the teacher and peers.

When you're done entering information, click Generate.

Step 3: Add to Your Design

Wait a moment while the AI generates your evaluation criteria based on what you entered. Once the rubric appears, click Add to Design.

Your AI-generated assessment rubric is now embedded in your Canva design.

AI-generated rubric on Canva

What's important here is the next part: review and edit the generated content to ensure it aligns with your curriculum and your students' skill level. The AI gives you a solid starting point, but your professional judgment should shape the final rubric.


Related Articles

How to Generate Multiple-Choice Questions on Diemdanh

Diemdanh.app is an EdTech platform built for educators and instructional technology professionals who want to streamline their teaching workflows in one place. The platform's AI-powered question generator makes it incredibly easy to build multiple-choice assessments aligned with your lesson content—no more spending hours crafting questions from scratch.

What's particularly useful about this feature is its versatility across different subjects and use cases. Whether you need quick formative checks during class, end-of-lesson review materials, practice problem sets, or a question bank for future use, Diemdanh handles it all. Teachers can fine-tune generated questions to match their specific student groups' proficiency levels. Here's exactly how to get started.

Creating Multiple-Choice Questions on Diemdanh.app: A Step-by-Step Guide

Step 1:

Head to Diemdanh.app using the link below and set up your account.

https://diemdanh.app/

Step 2:

Once you're logged in, click on the "Create Quiz" button at the bottom of the dashboard, as shown below.

Next, enter a title for your quiz and then select between Practice mode or Test mode (Test mode includes a countdown timer).

Step 3:

Scroll down and you'll see two approaches for generating multiple-choice questions on Diemdanh.app. The first option lets you upload a file or image as source material for the questions.

Alternatively, you can type in your requirements directly using the AI assistant. Just specify the topic, subject area, target audience, and how many questions you want generated. Then click the "Create" button to let the AI do the work.

Step 4:

After a brief processing period, your generated multiple-choice questions appear and are ready to use. Students answer the questions and then click Submit when finished.

In the "View Created Quizzes" section, you'll find several handy options. You can download an answer key file for distribution, share a shareable link with students to take the quiz, and more.

Created multiple-choice quiz on diemdanh.app


Related Articles

n8n tutorial - Lesson 22: AI Image Generation in n8n with gpt-image-1

n8n tutorial - Lesson 22: AI Image Generation in n8n with gpt-image-1

Hi everyone, in this session of our n8n workflow automation tutorial series, we cover how to fix broken image generation after OpenAI killed DALL-E, migrate to gpt-image-1, and extend the Content Factory with a YouTube metadata child workflow — all real steps from an actual n8n image generation AI build.

How to do:

Step 1 — Understand Why DALL-E Stopped Working

Before touching any node, confirm the root cause so you fix the right thing.
  1. OpenAI permanently shut down DALL-E 2 and DALL-E 3 on 12 May 2026 (announced 14 November 2025). Any call to model: "dall-e-3" returns error code model_not_found with the message "The model 'dall-e-3' does not exist" — there is no grace period.
  2. The original plan from the previous session was to swap the OpenAI node for an HTTP Request node and simply remove response_format. That partial fix is not enough because the model itself no longer exists.
  3. Web-search to confirm the shutdown date before making any code change — never rely solely on AI knowledge when the situation is time-sensitive.

Note — This is a recurring lesson in production automation: when an AI assistant's training data is older than the current date, always run a quick search to verify before acting on its suggestion.

Step 2 — Migrate the Image Generation Node to gpt-image-1

Replace the dead DALL-E call with gpt-image-1 and update the request body to match the new API contract.
  1. Open your T6-Content-Child-Blog workflow and locate the node that previously called DALL-E (either an OpenAI node or an HTTP Request node).
  2. In the HTTP Request node, set the Body to:
    • model: gpt-image-1
    • prompt: your prompt expression
    • size: 1024x1024
    • n: 1
  3. Remove any response_format field from the body — gpt-image-1 does not accept it and will error if it is present.

Tip — The endpoint URL stays the same (https://api.openai.com/v1/images/generations). Only the model name and body shape change, so keep your existing Authorization header and credentials untouched.

Step 3 — Handle the Base64 Response (Replace the Download Image Node)

gpt-image-1 returns a Base64 string, not a URL — the old Download Image node is now useless and must be replaced.
  1. Understand the critical difference:
    • DALL-E 3 returned: data[0].url — a public URL you could GET directly.
    • gpt-image-1 returns: data[0].b64_json — a raw Base64 string.
  2. Delete (or disable) the Download Image node that previously performed a GET request on the image URL.
  3. Add a Code node named Base64 to Binary immediately after the HTTP Request node.
  4. Inside the Code node, write logic to:
    • Read $json.data[0].b64_json from the previous node's output.
    • Convert it to a binary buffer.
    • Return it as a binary field named data so downstream nodes (e.g., Google Drive upload) can consume it.
  5. Connect the Code node output to your Google Drive upload node and confirm the binary field name matches what the Drive node expects.

Tip — After uploading, set the file permission to Anyone with the link / Reader (Make Public) in Google Drive. Without this, the thumbnail embed in your blog HTML (<img src="https://drive.google.com/thumbnail?id={id}&sz=w1024">) will return a 403 for public readers.

Step 4 — Fix the Draft Post URL and Post ID Fields

Verify the actual field names returned by the Blogger POST Draft node — two fields from the previous session were guessed incorrectly.
  1. Run the Create Draft node against a real Blogger API call and inspect the raw output JSON.
  2. Confirm field mappings:
    • postId → use {{ $json.id }} (top-level field — this guess was correct).
    • blogId → use {{ $json.blog.id }}.
    • blogUrldo not use {{ $json.url }} for a draft. For a DRAFT post, url only returns the blog homepage, not a permalink.
  3. For the edit link, construct it manually: https://www.blogger.com/blog/post/edit/{{ $json.blog.id }}/{{ $json.id }}

Note — A published post would populate url with the real permalink. Because this workflow saves drafts, the direct edit URL is more useful for review before publishing.

Step 5 — Build the YouTube Metadata Child Workflow

Create T6-Content-Child-YouTube as a 6-node workflow that generates YouTube SEO metadata and writes it to a Google Doc.
  1. Add a When Called by Another Workflow trigger node; define one input field: topic.
  2. Add an AI / Claude node (model: Claude Haiku 4.5) named YouTube SEO:
    • Connect it to a Structured Output Parser.
    • The prompt must demand JSON-only output with fields: title, description, tags, timestamps.
  3. Add a Code node named Format Doc Content to shape the parsed JSON into a readable Google Doc body string.
  4. Add a Google Docs node set to Create; note that the field holding the new document's ID in the output is id — not documentId (a common wrong guess).
  5. Add a second Google Docs node set to Update (Insert Text) to write the formatted content into the newly created document; reference the doc ID with {{ $json.id }}.
  6. Add a final Code node named Build YT Output; prefix all output fields with yt_ (e.g., yt_title, yt_tags, yt_docUrl, processedBy_YouTube) to prevent field collisions when Merging with Blog child output later.

Tip — This child workflow generates text metadata only — it does not create or upload a video. Auto-injecting this metadata into an actual YouTube upload requires a separate step: update the child to also write into the T5-Video-Metadata Sheet, which the upload workflow reads from.

Step 6 — Fix "Model Output Doesn't Fit Required Format" in the Output Parser

If the Structured Output Parser throws this error, tighten the prompt before reaching for advanced fixes.
  1. Edit the YouTube SEO node's system/user prompt to explicitly state: respond with JSON only, no markdown fences, no extra commentary, no trailing text.
  2. Test again — in most cases, this prompt strictness (Fix 1) resolves the error completely.
  3. The Auto-fixing Output Parser (Fix 2) is a more robust fallback that automatically retries malformed outputs. Keep this as a documented option for production hardening but do not implement it now unless Fix 1 fails.

Step 7 — Connect Both Children in the Parent Dispatch Workflow

Update T6-Content-Factory-Dispatch to fan out to both child workflows in parallel and merge their results.
  1. After the Limit node, draw two separate wires — one to Call Child Blog and one to Call Child YouTube.
  2. Set both Execute Sub-workflow nodes to Run once for each item so each topic spawns both children.
  3. Add a Merge node after both children; set its mode to Combine by Position.
  4. Connect both child output wires into the Merge node, then connect Merge to the Mark Done node.
  5. Test with one topic (e.g., "Top 5 amenities at Vinhomes Global Gate") and confirm:
    • Merge outputs exactly 1 item.
    • The item contains both blog fields and yt_-prefixed YouTube fields with no overwrites.

Production tip — The yt_ prefix on all YouTube child output fields is what prevents Merge from overwriting blog fields that share the same name (e.g., both children might output a title). Always prefix child outputs when multiple children feed a single Merge node.

Key Lessons from This Session

  1. DALL-E 2 and DALL-E 3 are permanently gone. Any workflow using those models must migrate to gpt-image-1 — there is no fallback or grace period.
  2. gpt-image-1 returns Base64, not a URL. Replace any "Download Image" node with a Code node that converts data[0].b64_json to a binary field.
  3. Draft Blogger posts do not return a real permalink. Build the edit URL manually from blog.id and id instead of relying on $json.url.
  4. Google Docs Create node returns id, not documentId. Always inspect raw output before writing expressions that reference node fields.
  5. Prefix child output fields to avoid Merge collisions. Use a consistent naming convention like yt_ for all fields from the YouTube child workflow.
  6. Prompt strictness fixes most Output Parser errors. Require JSON-only responses before reaching for the Auto-fixing Output Parser.
  7. Search before you fix, especially for API changes. When an AI tool suggests a fix for an API error, verify current model availability online first.

Conclusion:

In this n8n tutorial, we migrated image generation from the retired DALL-E to gpt-image-1, handled the Base64 response format correctly, fixed draft post field mappings, and built a parallel YouTube metadata child workflow — completing the core Content Factory. The next session focuses on production hardening: error output routing on each Execute Sub-workflow node, switching the parent trigger from Manual to Schedule, and linking an Error Handler workflow. If you have any questions, feel free to leave a comment below. Thank you!

Tags: n8n image generation AI, n8n tutorial, n8n workflow automation, gpt-image-1, n8n HTTP Request node, OpenAI image API, n8n sub-workflow, n8n Merge node

Maybe you are interested!

Build an Interactive Knowledge Train Drag-and-Drop Game Without Coding

Turning boring study questions into interactive games transforms how students engage with learning. Instead of students answering traditional questions one by one, educators can build dynamic drag-and-drop activities that turn practice sessions into play sessions. Here's what's interesting: you don't need any coding knowledge. With ChatGPT's help, you can generate a complete, functional HTML game from a single prompt.

This guide walks you through creating an interactive "Knowledge Train" game. The concept is elegant: students drag train cars onto tracks in the correct sequence, matching questions with answers. Each car contains two elements—the answer to the previous question on the left, and the next question on the right. This chain-linking approach makes knowledge connections visual and intuitive.

How to Build Your Knowledge Train Game

Step 1:

Open Gemini and switch to Canvas mode to begin building your game. Copy the prompt below into the interface.

Create an interactive HTML game called: KNOWLEDGE TRAIN.

Requirements:

- Build a standalone HTML file (HTML + CSS + JavaScript in one file) that works offline.

- Use bright 2D animations and colors suitable for elementary school students.

- Theme: educational train game.

- Include: locomotive, train tracks, multiple cars, and a draggable car depot.

- Students drag cars from the depot below onto the track in correct sequence.

Game Mechanics:

- The first car presents the opening question.

- Each car contains two sections:

 + Left side: ANSWER to the previous question.
 + Right side: NEXT QUESTION.

- When a car is placed correctly:
 
 + Car locks onto the track.
 + Play a success sound.
 + Show a subtle bounce effect.

- When a car is placed incorrectly:
 + Car returns to the depot.
 + Show a shake effect.
 + Play an error sound.

- Upon completion:
 + Display confetti animation.
 + Show congratulations message.
 + Animate the train moving left to right across the screen.

Layout:

- Top: "KNOWLEDGE TRAIN" title.

- Right side buttons:
 + Reset
 + Check
 + Shuffle

- Center area:
 + Locomotive on the left.
 + Empty slots for cars.
 + Horizontal scrollbar to view final cars.

- Bottom area:
 + Draggable car depot.
 + Horizontal scrollbar.

Data Structure (Teachers edit this):

const firstQuestion = "Who was the first king to establish our nation?";

const data = [

  {

    id: 1,

    answer: "King Hung",

    question: "According to legend, who invented sticky rice cakes and square cakes?",

  },

  {

    id: 2,

    answer: "Lang Lieu", 

    question: "Which three-year-old boy grew up overnight to fight invaders?",

  },

  {

    id: 3,

    answer: "Saint Giong",

    question: "Which two female war heroes rode elephants against enemy forces?",

  },

  {

    id: 4,

    answer: "The Two Trung Sisters",

    question: "Who placed wooden stakes in the Bach Dang River to defeat the Southern Han army?",

  },

  {

    id: 5,

    answer: "TEACHER ENTERS ANSWER",

    question: "TEACHER ENTERS NEXT QUESTION",

  },

  {

    id: 6,

    answer: "Ngo Quyen",

    question: "Complete!",

    label: "Finished"

  }

];

Technical Requirements:

- Enable mouse drag-and-drop functionality.

- Randomly shuffle cars in the depot.

- When a car is correctly placed, it disappears from the depot and appears on the track.

- Auto-scroll to the next empty slot when a car is added.

- Final car must always be draggable and never hidden.

- Clear horizontal scrollbars for both track and depot areas.

- Responsive design optimized for laptop screens.

- Large, readable fonts.

- No overlapping text or images.

- No external libraries required.

- Works completely offline.

- All code in a single HTML file.

Design Guidelines:

- Primary colors: sky blue, yellow, red, green.

- Rounded car corners with visible wheels.

- Left answer section: yellow background.

- Right question section: white background.

- Empty slots: dashed border outline.

- Fun effects without visual clutter.

Provide complete, production-ready HTML code so I can save it as .html and open it in Chrome immediately.

Step 2:

Wait a moment for the game to appear on the right side of your screen. Test it out. If you spot issues or want to adjust something, type your request in the left panel. Once satisfied, click the download icon to save the HTML file to your computer.

To play the game anytime, simply click the HTML file and it opens in any browser.

Here's what the game looks like in action. Students read questions, then drag and drop the correct cars to build their answer sequence and complete the train.


Related Articles

Copyright © 2016 QTitHow All Rights Reserved