Skip to content

Using PicGo in Node.js ​

Using PicGo in an existing Node.js project is straightforward. Point PicGo to a config file (or let it use the default one), and call upload once your configuration is valid.

Note

To support the local plugin system, PicGo only works in a Node.js environment (including the Electron main process). It does not support browser environments.

Initialization ​

If you need to initialize PicGo with a custom config file, see Configuration. Note that initialization differs across versions.

Use the default config file ​

Since v1.5.0+ ​

js
// since v1.5.0

// CommonJS
const { PicGo } = require('picgo')
// or ES modules
import { PicGo } from 'picgo'

const picgo = new PicGo() // <- Uses the default config file

Before v1.5.0 ​

js
// before v1.5.0

const PicGo = require('picgo')
const picgo = new PicGo() // <- Uses the default config file

Use a custom config file ​

Since v1.5.0+ ​

js
// since v1.5.0

// CommonJS
const { PicGo } = require('picgo')
// or es6
import { PicGo } from 'picgo'

const picgo = new PicGo('/xxx/xxx.json') // <- Pass the config file path when constructing

Before v1.5.0 ​

js
// before v1.5.0

const PicGo = require('picgo')
const picgo = new PicGo('/xxx/xxx.json') // <- Pass the config file path when constructing

Upload ​

js
const main = async () => {
  const res = await picgo.upload(['/xxx/xxx.jpg']) // <- Always pass an array, even if you only upload one image

  // Since 1.4.21 you can get the upload output
  console.log(res) // ['https:/xxx.com/xxx.jpg']
}

Specify a configuration for this upload 3.1.0+ ​

Pass uploader, configName, or configId in the second argument of picgo.upload(input, options) to use a saved uploader configuration for this upload. You do not need to call picgo.uploaderConfig.use() first.

js
// Use the Work configuration of the GitHub uploader.
const result = await picgo.upload(['/absolute/path/image.png'], {
  uploader: 'github',
  configName: 'Work'
})

// Configuration IDs are also supported. Replace this with the saved _id.
await picgo.upload(['/absolute/path/image.png'], {
  uploader: 'github',
  configId: 'your-config-id'
})

// Omitting input or passing an empty array still uploads from the clipboard.
await picgo.upload(undefined, { configName: 'Work' })

Configuration names are recommended. If you provide only a name or ID, PicGo searches across registered uploaders and requires exactly one match. When both are supplied, a unique ID match takes precedence; otherwise PicGo tries the name. See Per-upload configuration.

Each upload with configuration options uses an independent configuration. It does not change the global default uploader or save this choice to the configuration file, so uploads can use different configurations concurrently:

js
const [work, personal] = await Promise.all([
  picgo.upload(['/absolute/path/work.png'], {
    uploader: 'github',
    configName: 'Work'
  }),
  picgo.upload(['/absolute/path/personal.png'], {
    uploader: 'github',
    configName: 'Personal'
  })
])

Invalid options, missing configurations, or ambiguous matches reject the Promise with UploadOptionError. See the Upload API for error handling and types. Calls without these three parameters retain the previous configuration behavior, including normal plugin operations on global configuration.

PicGo Cloud 2.0+ ​

PicGo exposes a Cloud manager at picgo.cloud for authentication and user info (https://cloud.picgo.app).

Login ​

js
// Token login (verifies via Cloud API)
await picgo.cloud.login('YOUR_TOKEN')

// Browser-based login (opens a local callback server and a login URL)
await picgo.cloud.login()
  • If a token is provided, PicGo verifies it and saves it to settings.picgoCloud.token.
  • If no token is provided, PicGo tries the saved token first; if invalid, it starts a browser-based login flow to https://cloud.picgo.app.
  • You can cancel an in-progress browser login via picgo.cloud.disposeLoginFlow().

User info & logout ​

js
const info = await picgo.cloud.getUserInfo() // { user } | null
picgo.cloud.logout() // clears settings.picgoCloud.token

getUserInfo() returns null when no token is stored, and clears the token on 401/403 responses.

Local Server 2.0+ ​

PicGo exposes a local HTTP server via picgo.server.

js
// Enable server auth via config (optional)
picgo.saveConfig({ 'settings.server.secret': 'mytoken' })

// Start the server (uses config defaults when port/host are omitted)
const port = await picgo.server.listen()
console.log(picgo.server.getServerInfo())

// Stop it later
picgo.server.shutdown()

When authentication is enabled, POST /upload and all plugin routes require credentials. OPTIONS preflight is never blocked.

Credential priority is:

  1. Authorization: Bearer <token> (case-insensitive)
  2. X-PicGo-Secret
  3. ?secret=<token> (supported but discouraged; PicGo logs a warning once per process)

Example request:

js
await fetch('http://127.0.0.1:36677/upload', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer mytoken',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ list: [] })
})

Event listeners ​

When configuration options are supplied, lifecycle plugins and callbacks for beforeTransform, beforeUpload, afterUpload, and finished receive a ctx that reads this upload's configuration copy. Read uploader configuration with that ctx.getConfig() instead of a global configuration cached when the plugin was registered. See Per-upload context for details.

During the upload lifecycle, PicGo emits several events and passes useful parameters to event handlers.

If you need a refresher on the lifecycle diagram, see Overview.

uploadProgress ​

  • Parameter: Number
  • Description: upload progress. You can use it to drive a progress bar. Possible values are 0, 30, 60, 100, and -1. -1 means upload failed; 100 means upload succeeded.
js
picgo.on('uploadProgress', progress => {
  console.log(progress)
})

beforeTransform ​

  • Parameter: ctx
  • Description: fired before the input enters the transformer. You can read the input via ctx.input.
js
picgo.on('beforeTransform', ctx => {
  console.log(ctx.input) // ['/xxx/xxx.jpg']
})

beforeUpload ​

  • Parameter: ctx
  • Description: fired before the output enters the uploader. You can read the output after the transformer via ctx.output.
js
picgo.on('beforeUpload', ctx => {
  console.log(ctx.output) // [{ base64Image, fileName, width, height, extname }]
})

afterUpload ​

  • Parameter: ctx
  • Description: fired after the uploader successfully uploads. You can read the output after the uploader via ctx.output.
js
picgo.on('afterUpload', ctx => {
  console.log(ctx.output) // [{fileName, width, height, extname, imgUrl}] <- Note that imgUrl is now included.
})

finished ​

  • Parameter: ctx
  • Description: fired after the uploader succeeds and after afterUploadPlugins have run. Use it to get the final output.
js
picgo.on('finished', ctx => {
  console.log(ctx.output) // [{fileName, width, height, extname, imgUrl}] <- Note that imgUrl is now included.
})

failed ​

  • Parameter: error
  • Description: fired when an upload fails or an error is thrown during the lifecycle. You can catch the error here. (Before v1.2.10 you couldn’t get the error details, but you could still listen to this event.)
js
picgo.on('failed', error => {
  console.log(error) // error message
})

notification ​

  • Parameter: notice
  • Description: upload failure notifications emitted by an uploader. Listen to this to show user-facing messages.
js
picgo.on('notification', notice => {
  console.log(notice) // { title, body, text? }
})

title and body are always present. text is optional extra information (for example, a URL where the user can look up an error code) and can be undefined.

Lifecycle plugins ​

In addition to listening to lifecycle events, you can plug into those lifecycle stages to implement more advanced behaviors—for example, renaming files or compressing images in beforeUpload, or adding watermarks in beforeTransform.

PicGo exposes a helper object that contains plugin containers for the lifecycle stages. Register a plugin via register(). You register an object that must include a handle method, and PicGo will pass ctx into handle.

Note

Register your plugins before calling upload(), otherwise they won’t take effect.

helper.beforeTransformPlugins ​

Called after the beforeTransform event is emitted.

js
picgo.helper.beforeTransformPlugins.register('name', {
  handle: function (ctx) {
    console.log(ctx.input)
  }
})

picgo.upload(['/xxx/xxx.jpg'])

helper.beforeUploadPlugins ​

Called after the beforeUpload event is emitted.

js
picgo.helper.beforeUploadPlugins.register('name', {
  handle: function (ctx) {
    console.log(ctx.output)
  }
})

picgo.upload(['/xxx/xxx.jpg'])

helper.afterUploadPlugins ​

Called after afterUpload is emitted and before finished.

js
picgo.helper.afterUploadPlugins.register('name', {
  handle: function (ctx) {
    console.log(ctx.output)
  }
})

picgo.upload(['/xxx/xxx.jpg'])

If you want to build more advanced features (plugin-specific configuration, naming your plugin, publishing it for others), see Plugin Development.

Logging 1.3.7+ ​

PicGo’s logger module supports persistent log writing. You can call picgo.log.xxx to write logs, where xxx can be success, warn, info, or error.

Logger calls create a picgo.log file next to your PicGo config file, and the same logs are also printed to the console.

Example:

2019-04-18 13:52:58 [PicGo INFO] Before transform
2019-04-18 13:52:58 [PicGo INFO] Transforming...
2019-04-18 13:52:58 [PicGo INFO] Before upload
2019-04-18 13:52:58 [PicGo INFO] Uploading...
2019-04-18 13:53:01 [PicGo SUCCESS] 
https://xxxx.png

Loading third-party plugins 1.4.19+ ​

  • Since 1.4.19, PicGo exposes pluginHandler and pluginLoader for working with third-party plugins.
  • Since 1.5.0, PicGo also exposes use() to make manual plugin loading easier.

In short:

  • pluginHandler: install/update/uninstall plugins via npm.
  • pluginLoader: dynamically register/get/unregister plugins at runtime.

Both can be used to bring in plugins, but they differ:

  1. pluginHandler uses npm to install/uninstall plugins. This is persistent—after restarting PicGo, installed plugins are auto-loaded.
  2. pluginLoader is for dynamic runtime loading, useful when you need to load different plugins on the fly.

use 1.5.0+ ​

  • (plugin: IPicGoPlugin, name?: string): IPicGoPluginInterface

Manually load a third-party plugin. If the second parameter name is omitted, PicGo will instantiate the plugin without registering it into PicGo’s plugin list—this is handy for dynamic loading. Example:

js
const { PicGo } = require('picgo')
const PluginMigrater = require('picgo-plugin-pic-migrater')
const MinioUploader = require('picgo-plugin-minio')

const picgo = new PicGo()

const plugin = picgo.use(PluginMigrater) // will not register this plugin, just use it
picgo.use(MinioUploader, 'minio') // will register this plugin

picgo.setConfig({
  'picgo-plugin-pic-migrater': {
    newFileSuffix: '_new',
    include: '',
    exclude: ''
  },
  picBed: {
    current: 'minio',
    uploader: 'minio',
    minio: {
      endpoint: 'http://localhost:9000',
      accessKey: 'minioadmin',
      secretKey: 'minioadmin',
      bucket: 'picgo',
      path: '/',
      useSSL: false
    }
  }
})

// will use minio for migrating
plugin.migrateFiles(['/xxx/yyy.md']) // { total: number, success: number }

pluginHandler ​

PicGo exposes three methods corresponding to npm install, npm update, and npm uninstall.

All three methods accept an array. pluginName can be:

  1. The full package name, e.g. picgo-plugin-xxx.
  2. The short name, e.g. xxx.
  3. A scoped package, e.g. @xxx/picgo-plugin-yyy.
  4. A local path, e.g. ./xxx/yyy/picgo-plugin-zzz.

The result indicates whether the operation succeeded. Example:

js
const main = async () => {
  const res = await picgo.pluginHandler.install(['xxx'])
  if (res.success) {
    console.log(res.body) // ['picgo-plugin-xxx']
  } else {
    console.log(res.body) // error message
  }
}

See api-pluginHandler for details.

pluginLoader ​

  • registerPlugin(pluginName, plugin): register a plugin dynamically
  • unregisterPlugin(pluginName): unregister a plugin dynamically
  • getPlugin(pluginName): get a plugin
  • hasPlugin(pluginName): check whether a plugin exists

Example:

js
const pluginXXX = require('picgo-plugin-xxx')
console.log(picgo.pluginLoader.hasPlugin('xxx')) // false

// Note: pluginName must be unique
picgo.pluginLoader.registerPlugin('xxx', pluginXXX)

console.log(picgo.pluginLoader.hasPlugin('xxx')) // true

See api-pluginLoader for details.

Notes for bundling with Webpack ​

If you want to integrate PicGo into a Node.js project bundled by webpack (for example, an Electron project), you may see errors like Can't find module "." during bundling. This happens because webpack can’t reliably handle PicGo’s dynamic require() for plugins.

For PicGo, dynamically loaded plugins do not need to be bundled, because PicGo loads them at runtime rather than at build time. You can work around this by bypassing webpack’s require:

js
const requireFunc = typeof __webpack_require__ === 'function' ? __non_webpack_require__ : require
const PicGo = requireFunc('picgo')
const picgo = new PicGo()

For more background, see this issue。