How I built an in-memory explicit content filter in Node.js (200ms latency, zero images saved)
If you allow user-generated content in your app, you eventually run into a massive liability problem. Users will upload NSFW images. I ran into this exact problem when Apple rejected my previous app under Guideline 1.2 (User Generated Content). I needed a filter, but the standard way most tutorials teach you to handle this is flawed. Usually, the process goes like this: User uploads an image from…
Developing an in-memory explicit content filter for Node.js presents a significant challenge when dealing with user-generated content. This issue became evident when the author's previous app was rejected by Apple under Guideline 1.2 (User Generated Content). The conventional method of saving uploaded images to disk or cloud storage, followed by a background job that uses a machine learning model to check the image, proved flawed.
The explicit image would first be stored on the server's hard drive before the model could determine its appropriateness. If the background job failed or was delayed, the server would temporarily host illegal or policy-violating content. To address this, the author created a single Node.js endpoint that manages the entire classification process in memory.
This approach eliminates the need to save the image to disk by receiving the image as a buffer and passing it directly to a lightweight machine learning model. Once the classification is complete, the buffer is immediately destroyed, meaning the image never touches the server's hard drive. Using the open-source nsfwjs library and TensorFlow.js, the core logic of this in-memory filter involves decoding the image buffer, passing it to the model for classification, and then disposing of the tensor to free up memory.
The server receives the image through the multer.memoryStorage() method, ensuring it exists only in RAM for a brief moment before being discarded. This method provides total privacy, as the server does not store users' private photos. Additionally, it significantly speeds up the classification process, often completing in around 200ms per image on a standard VPS.
The simplicity of the approach allows for synchronous API calls, enabling the filter to run before database transactions, thereby maintaining clean backend architecture. To implement this solution, the provided code snippet can be used as a starting point. It is crucial to monitor server memory, as TensorFlow tensors can cause memory leaks if the .dispose() method is not called.
For those who prefer not to handle the ML models or RAM management themselves, the author has launched an API called Tabu that offers a free tier for testing purposes.
Written by urgent.news from Dev.to's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.