Waifu Board Provider Documentation
Waifu Board allows the community to write extensions for virtually any image or manga/doujinshi site.
There are two supported provider types:
- image-board → Gelbooru, Danbooru, Rule34, Sankaku, ychan, etc.
- book-board → NHentai, Hitomi.la, MangaDex, novel sites, etc.
this.type must be exactly "image-board" or "book-board". If it doesn’t match, the extension will be silently ignored on load.
Both provider types can be implemented in two different ways, depending on the target site:
- HTML-based providers – most sites require scraping raw HTML using Cheerio or the headless browser helper.
- API-based providers – some platforms expose clean REST endpoints (for example Danbooru, Waifu.pics, Pixiv mirrors or custom backends). In these cases the provider simply performs API calls and adapts the JSON responses to the formats expected by Waifu Board.
Installation & Development Notes
Extensions for Waifu Board are stored in the public community repository:
https://github.com/ItsSkaiya/WaifuBoard-Extensions
You can browse existing providers, submit your own, or use them as reference for new extensions.
How to install an extension
Until the built-in Extension Manager is implemented, installation is manual:
C:\Users\user\WaifuBoards\extensions
Drop your .js provider file inside this folder before opening the program.
Developer Tools
You can open DevTools inside the app at any time:
ALT + I → open DevTools
This is the easiest way to debug providers, inspect logs, HTML content, and network requests.
Constructor – Mandatory signature
Every provider receives three arguments:
constructor(fetchPath, cheerioPath, browser) {
this.fetch = require(fetchPath); // node-fetch
this.cheerio = require(cheerioPath); // static HTML parsing
this.browser = browser; // headless browser instance
this.type = "image-board"; // or "book-board"
}
Feel free to store anything else on this (base URL, default headers, cookies, rate-limit counters, etc.).
browser.scrape() – Headless browser helper
Use this when the site relies on JavaScript and static HTML parsing isn't enough.
await this.browser.scrape(url, evaluator, options)
async fetchSearchResult(query, page = 1) {
return await this.browser.scrape(
// URL loaded in the internal WebView
`https://rule34.xxx/?page=post&s=list&tags=${encodeURIComponent(query)}&pid=${(page-1)*42}`,
// Function evaluated INSIDE the webpage
() => ({
posts: [...document.querySelectorAll('span.thumb')].map(el => ({
id: el.id.slice(1),
thumb: el.querySelector('img').src
}))
}),
{
waitSelector: '#thumbnail-container',
timeout: 12000,
scrollToBottom: true,
renderWaitTime: 300,
loadImages: false,
args: [query, page]
}
);
}
Image-Board Providers
For sites where each post is a single illustration (Gelbooru style).
Image-Board Template (Scrapping raw HTML)
class MyImageBoard {
constructor(fetchPath, cheerioPath, browser) {
this.fetch = require(fetchPath);
this.cheerio = require(cheerioPath);
this.browser = browser;
this.type = "image-board";
}
async fetchSearchResult(query="", page=1, perPage=42) {
// MUST return:
// { results:[{ id, image, tags[], type:"preview" }], page, hasNextPage, nextPage }
return {
results: [],
page,
hasNextPage: false,
nextPage: page + 1
};
}
async fetchInfo(id) {
// MUST return:
// { id, fullImage, sampleImage?, tags[], createdAt, rating?, source }
return {
id,
fullImage: "",
sampleImage: "",
tags: [],
createdAt: Date.now(),
rating: "unknown",
source: ""
};
}
}
module.exports = { MyImageBoard };
Book-Board Providers
For manga, manhwa, doujinshi or text-based light novels.
Book-Board Template (Scrapping raw HTML)
class MyBookBoard {
constructor(fetchPath, cheerioPath, browser) {
this.fetch = require(fetchPath);
this.cheerio = require(cheerioPath);
this.browser = browser;
this.type = "book-board";
}
async fetchSearchResult(query="", page=1) {
// MUST return:
// { results:[{ id, image, title, tags[], sampleImageUrl?, type:"book" }], hasNextPage }
return {
results: [],
hasNextPage: false
};
}
async findChapters(mangaId) {
// MUST return:
// { chapters:[{ id, title, index, chapter?, language? }], cover }
return {
chapters: [],
cover: ""
};
}
async findChapterPages(chapterId) {
// MUST return ONLY ONE format:
// ----------------------------------------------------------
// IMAGE-BASED:
// [ { url, index, headers? } ]
// ----------------------------------------------------------
// TEXT-BASED:
// [ { type:"text", content, index } ]
// ----------------------------------------------------------
return [];
}
}
module.exports = { MyBookBoard };