Guide

How to create H5P content with ChatGPT - and get a file that actually imports

Most guides stop at the prompt. The hard part starts afterwards: turning the chat's answer into an .h5p package your LMS will accept. Here is the whole path, including the three ways it usually breaks.

If you have looked for a "ChatGPT to H5P" workflow, you have probably landed on a page of prompt recipes. They work - a good prompt gets you solid questions, sensible distractors and useful feedback. Then you are left holding a wall of text, and you still have to retype it into the H5P editor, field by field.

Generating the questions is only half the problem. This guide covers the other half: getting from the chat's answer to a file your LMS accepts.

Why "write me a quiz" is not enough

H5P activities are not documents. Each activity type has a semantics file that defines exactly which fields exist, what type each one is and how they nest. A Question Set is not a list of questions - it is a container whose every question is a separate sub-activity with its own library reference and its own parameter tree.

So a chat answer only becomes usable if it has a predictable shape. In practice that means three things in your prompt:

  • Ask for one JSON block and nothing else. No preamble, no explanation after it. Anything outside the block is something you have to clean up by hand.
  • Fix the schema in advance. Give the model the exact field names you expect and tell it they must not change. Models are happy to rename answers to options if you leave the door open.
  • Constrain the HTML. Allow a short list of tags - paragraphs, lists, bold, emphasis - and forbid the rest. H5P strips unknown markup silently, and "silently" is the problem.

None of this is exotic. It is the difference between an answer you can process and an answer you have to read.

Say what language means, not just which language

"Write it in German" is an incomplete instruction. German has a formal and an informal address; so does French and Italian. Swedish and Norwegian effectively do not - modern usage addresses everyone directly, and the polite form now reads as archaic or condescending. Portuguese splits into European and Brazilian conventions that differ in grammar, not only vocabulary.

A model left to guess will pick one at random, and often switch halfway through. In a compliance course that is not a stylistic detail: it is the difference between material that sounds written for the learner and material that sounds machine-translated at them.

Put the convention in the prompt explicitly. One sentence per language is enough.

Three ways the import fails

You have your JSON, you have built a package, you upload it - and the LMS refuses. These are the failures worth knowing about, because the error messages point in the wrong direction.

1. "Missing required library ..."

This is the most common one, and it reads like a defect in your file. Often it is not.

Before accepting an upload, H5P collects the libraries it finds in the package and checks what each of them still needs. That check covers three kinds of dependency, not one - you can read it in the H5P PHP core, in H5PValidator::getMissingLibraries(), which walks preloadedDependencies, dynamicDependencies and editorDependencies in turn. The first two are documented widely; the third is the one that surprises people.

Editor libraries take no part in playback, and H5P's own export leaves them out on the assumption that the receiving platform pulled them from the H5P Hub. A platform a few versions behind, or one that never installed that particular activity type, does not have them - so the whole package is rejected over something the learner would never see.

The same message can also mean something completely different. Library files inside the package are only inspected if the uploading user is allowed to install libraries at all; without that permission they are skipped, and the validator then reports them as missing. A package requiring a newer H5P core than the site runs fails separately, with an unsupported-API-version error.

So there are two sides to the fix. On the receiving side: update the H5P plugin, install that activity type once from the Hub, or check that the account may install libraries. On the producing side, if you control packaging, include the editor libraries as well. That makes imports markedly more portable - in our own generator the widest case, Course Presentation, grew by about 1.6 MB uncompressed - but it does not eliminate every case, because permissions and core version are not yours to control.

2. The package is rejected wholesale over one entry

H5P validates the file extension of every single entry in the archive. Two consequences that surprise people:

  • A directory entry has no extension at all. Some ZIP writers add them by default, and each one produces a "File ... not allowed" error. One package can fail with dozens of errors that all trace back to this.
  • Any stray file inside a library folder counts too - a leftover .bak from editing a translation, an editor's temporary file. One of them fails the entire upload, not just itself.

This is not theoretical. H5P's own support forum has people who unzipped a working package, rezipped it without changing anything, and got back a wall of File "blob-1.0/" not allowed - the directory entries their zip tool had helpfully added.

ZIP reconstructs the folder structure from file paths, so directory entries add nothing. Leave them out and filter everything else against H5P's allow-list before packing.

3. It imports cleanly - and a setting is quietly dead

This is the nastiest one, because nothing warns you. H5P runs your parameters through a content validator that removes anything the activity's semantics does not recognise. No error, no message. The activity appears, works, and one of your settings simply has no effect.

The classic case is a field nested one level too deep. H5P flattens groups that contain exactly one field - the group does not get its own level in the parameters. Write the nested form and you have created configuration that nothing will ever read.

Note that both outcomes are possible and neither is loud. An unrecognised key sitting on an object is usually stripped. A value of the wrong shape - a list where an object belongs - is often not stripped at all; it is simply never read. Either way the package passes import validation, the activity appears and works, and the setting does nothing. It surfaces weeks later, when someone asks why the feedback thresholds they configured have no effect.

If you build packages yourself, this is the case worth testing for deliberately: compare what you put in against what the validator gives back, and treat any field that disappeared as a bug.

What the AI still does not do

AI writes a first draft. It does not know which misconception your learners actually have, which distractor is tempting for the right reason, or whether a question is worth asking at all. In our own course production the model saves the typing, not the thinking - and the review pass is not optional.

It is also weak at calibration. Ask for "basic level" and you tend to get questions that are either trivially easy or quietly assume prior knowledge. Say who the learner is and what they should be able to do afterwards, and the draft improves more than any prompt trick will manage.

A shortcut, if you want one

We do all of the above in production, so we packaged it as a free AI H5P generator. You answer a short brief, it writes the prompt for you, you paste that into the AI you already use, and you paste the answer back. It validates the structure and builds the .h5p file - editor libraries included, so it imports on platforms that are behind.

  • No account, no install. It runs in a browser tab.
  • No credits. Your own AI does the writing, so there is nothing to bill.
  • No file upload. Your source document stays in your chat and never reaches our server.

Fourteen activity types, including Question Set and Course Presentation. Content in eleven languages - English, German, Spanish, French, Italian, Dutch, Brazilian Portuguese, Swedish, Norwegian, Polish and Czech - each with its own address conventions written into the prompt.

Open the generator - free

Or read more about it on our free tools page.

Related

H5P® is a registered trademark of the H5P Group. This article and our tools are not affiliated with or endorsed by H5P Group.

We use cookies to analyse site traffic and measure ad performance. Privacy policy